We are seeing some hard to reproduce issues that seem to relate to the SQL server and how we communicate with it, and I'm investigating if we might be using DBContext in conjunction with Task wrong.
We have a signalR hub used my many different clients. When we reach a certain level of clients, the system slows down and things will eventually stop working.
The signalR is similar to this example, but with many more async methods:
namespace Test.Webservice.Hubs
{
public class ExampleHub : Hub<ExampleClientContract>, IExampleHub
{
private readonly ILogger _logger;
private readonly IExampleRepository _exampleRepo;
public ExampleHub(ILogger logger, IExampleRepository exampleRepo)
{
_logger = logger;
_exampleRepo = exampleRepo;
}
public async Task<IEnumerable<ExampleTopicState>> GetExampleStates(Guid operationId)
{
var examples = await _exampleRepo.GetExampleStatesAsync(operationId);
return examples.Select(ExampleTopicState.Create);
}
}
}
The ExampleRepository looks something like this, but again with many more methods:
namespace Test.DataAccess.Repository
{
public class ExampleRepository : IExampleRepository
{
private readonly ILogger _logger;
private readonly ExampleContext _context;
private readonly IExampleRepositoryMapping _repositoryMapping;
public ExampleRepository(ILogger logger, IExampleRepositoryMapping repositoryMapping)
{
_repositoryMapping = repositoryMapping;
_logger = logger;
_context = new ExampleContext();
}
public async Task<IEnumerable<ExampleDto>> GetExampleStatesAsync(Guid operationId)
{
IEnumerable<Example> result = null;
await Task.Factory.StartNew(() =>
{
result = _context
.Examples.Where(c => c.OperationId.Equals(operationId))
.GroupBy(o => o.Type)
.SelectMany(p => p.GroupBy(q => q.Topic))
.Select(o => o.FirstOrDefault(
n => n.ExampleTimeUtc == o.Max(d => d.ExampleTimeUtc)));
});
return _repositoryMapping.Mapper.Map<IEnumerable<ExampleDto>>(result);
}
}
}
Is it correct to use DbContext inside wait Task.Factory.StartNew, or could this lead to issues? This SO answere seems to say that it could be problematic, but I'm not sure if I understand it fully.
Edit:
Thought id add en example on how the hub is called from one of the clients:
var loadingTasks = _connectorMap.Select(o => (System.Action) ( () =>
{
var result = o.Proxy.Invoke<ExampleResult>(
"GetExampless",
_connectedOperations.Where(c => o.HubConnection.Url.StartsWith(c.ExampleWebService)).Select(s => s.UniqueId),
filter.TimeFilter.Start,
filter.TimeFilter.End,
filter.TopicFilter,
filter.SeverityLevelFilter,
currentPage, pageSize,
filter.IsGrouped).Result;
_results.Add(result);
}));
Parallel.ForEach(loadingTasks, lt => lt());