I have this action on one of my controllers which is called by another method which has been called also by another action.
All works fine, unless I try to en-queue with Hangfire
some jobs: _bankClient.FetchAndEnsureTransactionsAsync
and _bankClient.RefreshItemAsync
.
This is causing the application to freeze (the client, browser, stops while the server is still running). I suppose is some weird deadlock
, but nothing I've tried seems to make it work!
Would someone know how to solve this problem?
I'm aware Hangfire
does not support yet calling async
methods, so I have the synchronous
version of this methods which I en-queue.
NOT working action
private async Task<ActionResult> ActionOnFinished(long itemId, ItemStatus status, Guid userId)
{
var seller = await _unitOfWork.CompanyRepository.GetCompanyByUserIdAsync(userId).ConfigureAwait(false);
await _bankClient.CreateItemAndAccountsAsync(userId, seller.Id, itemId, seller.Name, seller.Siren.ToString()).ConfigureAwait(false);
// TODO: use hangfire when available and fire this on BackgroundJob
if (Properties.Settings.Default.EnableHangfire)
{
BackgroundJob.Schedule<IBankClientService>(bs => bs.FetchAndEnsureTransactions(userId), DateTimeOffset.Now.AddMinutes(1));
BackgroundJob.Schedule<IBankClientService>(bs => bs.RefreshItem(userId), DateTimeOffset.Now.AddMinutes(1));
}
else
{
await _bankClient.FetchAndEnsureTransactionsAsync(userId).ConfigureAwait(false);
await _bankClient.RefreshItemAsync(userId).ConfigureAwait(false);
}
return RedirectToAction(MVC.Dashboard.MyProfile());
}
Working action :
private async Task<ActionResult> ActionOnFinished(long itemId, ItemStatus status, Guid userId)
{
var seller = await _unitOfWork.CompanyRepository.GetCompanyByUserIdAsync(userId).ConfigureAwait(false);
await _bankClient.CreateItemAndAccountsAsync(userId, seller.Id, itemId, seller.Name, seller.Siren.ToString()).ConfigureAwait(false);
// TODO: use hangfire when available and fire this on BackgroundJob
await _bankClient.FetchAndEnsureTransactionsAsync(userId).ConfigureAwait(false);
await _bankClient.RefreshItemAsync(userId).ConfigureAwait(false);
return RedirectToAction(MVC.Dashboard.MyProfile());
}
The precedent action is called by a private method:
private async Task<ActionResult> SelectActionByStatus(long itemId, ItemStatus status, Guid userId)
{
try
{
if (status.Status == RefreshStatusValues.Finished)
{
return await ActionOnFinished(itemId, status, userId).ConfigureAwait(false);
}
return ActionOnError();
}
catch (Exception ex)
{
_logger.Error(ex, nameof(SelectBank));
throw new ValidationFailureException(nameof(GetAccounts), ex.Message);
}
}
This action has been called by another action:
public async virtual Task<ActionResult> CallBack(string item_id)
{
try
{
var itemId = long.Parse(item_id);
var userId = CurrentUserId.Value;
// as this action is being called by a child window whom is being closed we need to configure the awaiter with ConfigureAwait(false)
var status = await _bankClient.CheckItemStatusAsync(userId, itemId).ConfigureAwait(false);
return await SelectActionByStatus(itemId, status, userId).ConfigureAwait(false);
}
catch (Exception ex)
{
_logger.Error(ex, nameof(CallBack));
return RedirectToAction(MVC.Bank.BankError());
}
}
SYNCHRONOUS VERSION: being enqueued:
public IEnumerable<Transaction> FetchAndEnsureTransactions(Guid userId)
{
try
{
return FetchAndEnsureTransactionsAsync(userId).ConfigureAwait(false).GetAwaiter().GetResult();
}
catch (Exception ex)
{
_logger.Error(ex, $"{nameof(FetchAndEnsureTransactions)}");
throw;
}
}
public void RefreshItem(Guid userId)
{
try
{
RefreshItemAsync(userId).ConfigureAwait(false).GetAwaiter().GetResult();
}
catch (Exception ex)
{
_logger.Error(ex, $"{nameof(RefreshItem)}");
throw;
}
}