Web api срабатывает быстрее чем фоновые приложения
Структура моего проекта
BackgroundRunnerInput - Получает сообщение, обрабатывает и отправляет в BackgroundRunnerOutput
using BackgroundRunnerInput;
IHost host = Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
services.AddHostedService<Worker>();
})
.Build();
await host.RunAsync();
Worker(BackgroundRunnerInput)
namespace BackgroundRunnerInput
{
public class Worker : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
StatisticOfTest statistic = new StatisticOfTest();
SolutionService solution = new SolutionService();
var factory = new ConnectionFactory
{
HostName = "rabbitmq",
};
IConnection connection = factory.CreateConnection();
IModel channel = connection.CreateModel();
IModel channel2 = connection.CreateModel();
channel.QueueDeclare("Input", exclusive: false, autoDelete: false, durable: false);
channel2.QueueDeclare("Output", durable: false, exclusive: false, autoDelete: false, arguments: null);
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, eventArgs) =>
{
Console.WriteLine("Recieved Event");
try
{
var body = eventArgs.Body.ToArray();
var jsonStr = Encoding.UTF8.GetString(body);
SolutionAddModel solutionAdd = JsonConvert.DeserializeObject<SolutionAddModel>(jsonStr);
statistic = solution.Validating(solutionAdd);
IBasicProperties props = channel.CreateBasicProperties();
props.MessageId = eventArgs.BasicProperties.MessageId;
if (String.IsNullOrEmpty(statistic.ErrorWhileCompiling))
{
statistic = solution.Create(solutionAdd);
jsonStr = JsonConvert.SerializeObject(statistic);
body = Encoding.UTF8.GetBytes(jsonStr);
channel2.BasicPublish(exchange: "", routingKey: "Output", mandatory: false, props, body: body);
Console.WriteLine("OutputSend");
}
else
{
jsonStr = JsonConvert.SerializeObject(statistic);
body = Encoding.UTF8.GetBytes(jsonStr);
channel2.BasicPublish(exchange: "", routingKey: "Output", mandatory: false, props, body: body);
Console.WriteLine("OutputSend");
}
Console.WriteLine($"Message received: {jsonStr}");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
};
channel.BasicConsume("Input", autoAck: true, consumer: consumer);
Console.WriteLine(" Press [enter] to exit.(RunnerInput)");
Console.ReadLine();
}
}
}
}
BackgroundRunneroutput - Получает обработанное сообщение от BackgroundRunnerInput и полученные результаты записывает в БД
using BackgroundRunnerOutput;
using ContestApi.DataAccess;
using Microsoft.EntityFrameworkCore;
IHost host = Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
services.AddHostedService<Worker>();
services.AddDbContext<ContestApiContext>(options =>
{
options.UseNpgsql("Server = postgres; Port = 5432; Database = ContestApi; User Id = postgres; Password = 123;");
});
})
.Build();
await host.RunAsync();
Worker(BackgroundRunnerOutput)
namespace BackgroundRunnerOutput
{
public class Worker : BackgroundService
{
private readonly ContestApiContext _context;
public Worker(ContestApiContext context)
{
_context = context;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
StatisticOfTest statistic;
OutputSaveService outputSaveService = new OutputSaveService(_context);
var factory = new ConnectionFactory()
{
HostName = "rabbitmq",
};
var connection = factory.CreateConnection();
var channel = connection.CreateModel();
channel.QueueDeclare(queue: "Output", durable: false, exclusive: false, autoDelete: false, arguments: null);
Console.WriteLine(" [*] Waiting for messages.");
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
Guid id = Guid.Parse(ea.BasicProperties.MessageId);
var body = ea.Body.ToArray();
var message = Encoding.UTF8.GetString(body);
statistic = JsonConvert.DeserializeObject<StatisticOfTest>(message);
outputSaveService.Save(statistic, id);
Console.WriteLine(" [x] Received {0}", message);
};
channel.BasicConsume(queue: "Output", autoAck: true, consumer: consumer);
Console.WriteLine(" Press [enter] to exit.(RunnerOutput)");
Console.ReadLine();
}
}
}
}
ContestApi.Web controller - проверяет есть ли ему нужные записи в бд и возвращает их
namespace ContestApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class SolutionsController : Controller
{
private readonly IMessageSender _messageSender;
private readonly ContestApiContext _context;
public SolutionsController(IMessageSender messageSender, ContestApiContext context)
{
_messageSender = messageSender;
_context = context;
}
[HttpPost]
public async Task<IActionResult> CreateSolution([FromBody] SolutionAddModel solutionAdd)
{
StatisticOfTest statistic = new StatisticOfTest();
var messageId = Guid.NewGuid();
_messageSender.SendMessage(solutionAdd, messageId);
if (_context.TestsStatistic.Any(u => u.Id == messageId))
{
var recordInStatistic = _context.TestsStatistic.Where(_context => _context.Id == messageId).FirstOrDefault();
statistic.Id = messageId;
statistic.ErrorWhileCompiling = recordInStatistic.ErrorWhileCompiling;
if (String.IsNullOrEmpty(recordInStatistic.ErrorWhileCompiling))
{
var recordsInSeTStatistic = _context.SetsStatistic.Where(_context => _context.Id == messageId).ToList();
statistic.SetsStatistic = new List<CurrentSetStatistic>();
for(int i = 0; i < recordsInSeTStatistic.Count; i++)
{
CurrentSetStatistic currentSet = new CurrentSetStatistic();
currentSet.IdSet = recordsInSeTStatistic[i].TaskId;
currentSet.ErrorWhileRunning = recordsInSeTStatistic[i].ErrorWhileRunning;
currentSet.OutputEqualToExpected = recordsInSeTStatistic[i].OutputEqualToExpected;
currentSet.Time = recordsInSeTStatistic[i].Time;
currentSet.Memory = recordsInSeTStatistic[i].Memory;
statistic.SetsStatistic.Add(currentSet);
}
return Ok(statistic);
}
return Ok(statistic);
}
return BadRequest("Нету такой записи в БД");
}
}
}
Проблема в том, что контроллер срабатывает быстрее фоновых задач и естественно не находит нужные ему записи во время проверки if (_context.TestsStatistic.Any(u => u.Id == messageId))
EDIT
Вот как web api связан с фоновыми приложениями
namespace ContestApi.Domain.RabbitMQ
{
public class RabbitMQProducerService : IMessageSender
{
public void SendMessage<T>(T message, Guid id)
{
var messageId = id.ToString();
var factory = new ConnectionFactory()
{
HostName = "rabbitmq",
};
var connection = factory.CreateConnection();
var channel = connection.CreateModel();
IBasicProperties props = channel.CreateBasicProperties();
props.MessageId = messageId;
channel.QueueDeclare("Input", exclusive: false, autoDelete: false, durable:false);
var json = JsonConvert.SerializeObject(message);
var body = Encoding.UTF8.GetBytes(json);
channel.BasicPublish(exchange: "", routingKey: "Input", props, body: body);
Console.WriteLine(" [x] Sent2 {0}", message);
Console.WriteLine(" Press [enter] to exit.(Domain)");
}
}
}
