Запуск задач по расписанию в Quartz.NET
Проект asp.net core 3.1 web-api. Возникла необходимость автоматической отправки с определенной периодичностью POST-запросов на сторонний сервис, получения с него данных и записи их в БД.
Реализацию пытаюсь делать через фреймверк Quartz.NET. Она получается следующая, не уверен что верная, поправьте пожалуйста где не верно:
public interface IRequestSender
{
Task<ResponseMessageDataQRCode> SendRequestAsync(string url, IEnumerable<KeyValuePair<string, string>> data, string str);
public Task<ReportQrCodeExchange> RequestQRcodesReceiving(string url, Dictionary<string, string> requestDataDict);
}
Класс реализующий интерфейс IRequestSender и отвечающий за всю работу (отправка запроса, получение ответа, обработка и запись ответа в БД через dbcontext):
public class RequestSender : IRequestSender
{
private readonly HttpClient httpClient;
private ServicesQRcodes _servicesQRcodes;
public RequestSender()
{
httpClient = new HttpClient();
_servicesQRcodes = new ServicesQRcodes();
}
public async Task<ReportQrCodeExchange> RequestQRcodesReceiving(string url, Dictionary<string, string> requestDataDict)
{
ReportQrCodeExchange reportQrCodeExchange = new ReportQrCodeExchange();
ResponseMessageDataQRCode responseData = null;
try
{
responseData = await SendRequestAsync(url, requestDataDict, "");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
if (responseData != null)
{
if (responseData.status.Equals("200") || responseData.status.Equals("OK"))
{
try
{
ResponseMessageDataQRCodeSuccessfully responseMessageDataQRCodeSuccessfully = (ResponseMessageDataQRCodeSuccessfully)responseData;
reportQrCodeExchange = _servicesQRcodes.CheckQrCodes(responseMessageDataQRCodeSuccessfully);
}
catch
{
ResponseMessageDataQRCodeError responseMessageDataQRCodeError = (ResponseMessageDataQRCodeError)responseData;
foreach (string str in responseMessageDataQRCodeError.items)
{
responseMessageDataQRCodeError.items.Append(str);
}
reportQrCodeExchange.error = responseData.error;
reportQrCodeExchange.status = responseData.status;
reportQrCodeExchange.dateTimeRequest = responseData.date;
}
}
else
{
reportQrCodeExchange.error = responseData.error;
reportQrCodeExchange.status = responseData.status;
reportQrCodeExchange.dateTimeRequest = responseData.date;
return reportQrCodeExchange;
}
}
return reportQrCodeExchange;
}
public async Task<ResponseMessageDataQRCode> SendRequestAsync(string url, IEnumerable<KeyValuePair<string, string>> data, string str)
{
ResponseMessageDataQRCode responseData = null;
using var request = new HttpRequestMessage(HttpMethod.Post, url)
{
Content = new FormUrlEncodedContent(data)
};
request.Headers.Add("Application", "remoteData");
var response = await httpClient.SendAsync(request).ConfigureAwait(false);
string jsonResponseData = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
if (FindItemsToken(jsonResponseData) == JsonTokenType.StartObject) //indxF==-1 && indxL==-1 && indxF>=indxL
{
responseData = JsonSerializer.Deserialize<ResponseMessageDataQRCodeSuccessfully>(jsonResponseData);
}
else if (FindItemsToken(jsonResponseData) == JsonTokenType.StartArray)
{
responseData = JsonSerializer.Deserialize<ResponseMessageDataQRCodeError>(jsonResponseData);
}
}
else
{
responseData = JsonSerializer.Deserialize<ResponseMessageDataQRCodeError>(jsonResponseData);
}
return responseData;
}
//Проверка типа объекта в JSON после имени свойства "items"
private static JsonTokenType FindItemsToken(string json)
{
var reader = new Utf8JsonReader(Encoding.UTF8.GetBytes(json));
while (reader.Read())
{
if (reader.TokenType == JsonTokenType.PropertyName && reader.GetString() == "items")
break;
}
if (!reader.Read()) return JsonTokenType.None;
return reader.TokenType;
}
}
}
Класс непосредственно запускающий экземпляр задачи/работы:
[DisallowConcurrentExecution]
public class RequestJob : IJob
{
private readonly IRequestSender _requestSender;
private readonly string url = "https://хххххх/app/api/barcodes/get.php";
public RequestJob(IRequestSender requestSender)
{
this._requestSender = requestSender;
}
public Task Execute(IJobExecutionContext context)
{
string dateTimeRequestStr;
DateTime dateTimeUTC = DateTime.UtcNow;
dateTimeRequestStr = dateTimeUTC.AddHours(3).ToString("yyyy-MM-dd hh:mm:ss");
Dictionary<string, string> requestMessageDict = new Dictionary<string, string>
{
["token"] = "N2U1OThkZDZkZDliZGFiM/lAfhoRNk0D+iJh2Z1h1fpYEUWXkzsbvGg1",
["date"] = dateTimeRequestStr
};
_requestSender.RequestQRcodesReceiving(url,requestMessageDict);
// отправили запрос, получили ответ, записали в БД данные ответа
return Task.CompletedTask;
}
}
Класс фабрики управляющей запускам задач/работ:
public class SingletonJobFactory : IJobFactory
{
private readonly IServiceProvider _serviceProvider;
public SingletonJobFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
return _serviceProvider.GetRequiredService(bundle.JobDetail.JobType) as IJob;
}
public void ReturnJob(IJob job)
{
}
}
Настройка всего этого в Startup.cs:
services.AddQuartz(q =>
{
q.UseMicrosoftDependencyInjectionScopedJobFactory();
// Create a "key" for the job
var jobKey = new JobKey("RequestJob");
// Register the job with the DI container
q.AddJob<RequestJob>(opts => opts.WithIdentity(jobKey));
// Create a trigger for the job
q.AddTrigger(opts => opts
.ForJob(jobKey) // link to the RequestJob
.WithIdentity("RequestJob-trigger") // give the trigger a unique name
.StartNow()
.WithSimpleSchedule(x =>
x.WithIntervalInMinutes(1)
.RepeatForever()));
});
services.AddQuartzHostedService(q => q.WaitForJobsToComplete = true);
Выставил интервал 1 минуту в настройках services.AddQuartz в Startup.cs, поставил точку остановы в классе RequestJob : IJob, запустил в режиме отладки, по идее если бы задача запустилась бы, тчк остановы должна была сработать, о она не сработала, значит где-то ошибка, не пойму где?