Hangfire 1.6.19 .net core 2.1
你好, 当我在“周期性作业”中调用WebApi时,该作业将由于调用超时而失败,因此我使用异步方法进行调用,但是通过这种方式,所有作业均成功执行,并且无法反映WebApi调用是否成功或失败。
所以我判断了异步请求的回调方法。如果WebApi返回异常,则作业状态更改为失败。
但是,我的修改导致Hangfire失败的作业列表无法正常工作。 Hangfire是否提供内部方法来修改工作状态,或者您有更好的解决方案?
我的代码如下:
[AutomaticRetry(Attempts = 0)]
[DisplayName("InvokeApi,apiUrl:{0}")]
public void InvokeApi(string apiUrl, PerformContext context)
{
var invocationData = InvocationData.Serialize(context.BackgroundJob.Job);
int.TryParse(context?.BackgroundJob.Id, out var jobId);
var client = new RestClient(apiUrl)
{
Timeout = -1,
ReadWriteTimeout = -1
};
var request = new RestRequest(Method.GET)
{
Timeout = -1,
ReadWriteTimeout = -1
};
client.ExecuteAsync(request, response =>
{
if (!response.IsSuccessful)
{
using (var dbContext = new HangfireContext())
{
using (var transaction = dbContext.Database.BeginTransaction())
{
var state = dbContext.State.FirstOrDefault(x =>
x.JobId == jobId && x.Name == "Succeeded");
if (state != null)
{
state.Name = "Failed";
state.Reason = $"StatusDescription={response.StatusDescription},ErrorMessage={response.ErrorMessage ?? "null"}";
}
var job = dbContext.Job.FirstOrDefault(x => x.Id == jobId);
if (job != null)
{
job.StateName = "Failed";
job.InvocationData = Serialize(invocationData);
}
var counter =
dbContext.AggregatedCounter.FirstOrDefault(x => x.Key == "stats:succeeded");
if (counter != null) counter.Value = counter.Value - 1;
dbContext.SaveChanges();
transaction.Commit();
}
}
}
});
}
public string Serialize(InvocationData invocationData)
{
var parameterTypes = JobHelper.FromJson<string[]>(invocationData.ParameterTypes);
var arguments = JobHelper.FromJson<string[]>(invocationData.Arguments);
return JobHelper.ToJson(new MyJobPayload
{
TypeName = invocationData.Type,
MethodName = invocationData.Method,
ParameterTypes = parameterTypes != null && parameterTypes.Length > 0 ? parameterTypes : null,
Arguments = arguments != null && arguments.Length > 0 ? arguments : null
});
}
public class MyJobPayload
{
[JsonProperty("type")]
public string TypeName { get; set; }
[JsonProperty("m")]
public string MethodName { get; set; }
[JsonProperty("p", NullValueHandling = NullValueHandling.Ignore)]
public string[] ParameterTypes { get; set; }
[JsonProperty("a", NullValueHandling = NullValueHandling.Ignore)]
public string[] Arguments { get; set; }
}
期待您的回复,谢谢!
答案 0 :(得分:0)
它终于成功了,但是有更好的方法吗?
[AutomaticRetry(Attempts = 0)]
[DisplayName("InvokeApi,apiUrl:{0}")]
public void InvokeApi(string apiUrl, PerformContext context)
{
var invocationData = InvocationData.Serialize(context.BackgroundJob.Job);
int.TryParse(context?.BackgroundJob.Id, out var jobId);
var dtBegin = DateTimeOffset.Now;
var client = new RestClient(apiUrl)
{
Timeout = -1,
ReadWriteTimeout = -1
};
var request = new RestRequest(Method.GET)
{
Timeout = -1,
ReadWriteTimeout = -1
};
client.ExecuteAsync(request, response => {
if (!response.IsSuccessful)
{
var responseMessage = $"TotalSeconds={DateTimeOffset.Now.Subtract(dtBegin).TotalSeconds},StatusDescription={response.StatusDescription},ErrorMessage={response.ErrorMessage ?? "null"}";
try
{
var strHangfireDataContext = EngineContext.Instance.ServiceProvider.GetService<ConnectionStringsConfiguration>().HangfireDataContext;
var optionsBuilder = new DbContextOptionsBuilder<HangfireContext>();
optionsBuilder.UseSqlServer(strHangfireDataContext);
using (var dbContext = new HangfireContext(optionsBuilder.Options))
{
using (var transaction = dbContext.Database.BeginTransaction())
{
var state = dbContext.State.FirstOrDefault(x =>
x.JobId == jobId && x.Name == "Succeeded");
if (state != null)
{
var failedState = new FailedState(new Exception(responseMessage));
state.Name = failedState.Name;
state.Reason = failedState.Reason;
state.Data = JobHelper.ToJson(failedState.SerializeData());
}
var job = dbContext.Job.FirstOrDefault(x => x.Id == jobId);
if (job != null)
{
job.StateName = "Failed";
job.InvocationData = JobHelper.ToJson(new
{
Type = invocationData.Type,
Method = invocationData.Method,
ParameterTypes = invocationData.ParameterTypes,
Arguments = invocationData.Arguments
});
}
var counter =
dbContext.AggregatedCounter.FirstOrDefault(x => x.Key == "stats:succeeded");
if (counter != null) counter.Value = counter.Value - 1;
dbContext.SaveChanges();
transaction.Commit();
}
}
}
catch (Exception ex)
{
_logger.LogError("Exception jobId:" + jobId + ";ex:" + ex.ToString());
}
}
});
}