Queuing BankgroundJob with Hangfire within an async action in ASP.NET MVC freeze the application

雨燕双飞 提交于 2019-12-24 03:30:03

问题


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;
        }
    }

来源:https://stackoverflow.com/questions/39485570/queuing-bankgroundjob-with-hangfire-within-an-async-action-in-asp-net-mvc-freeze

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!