How to use asynchronous code in scheduled job (ScheduledPlugin)

Vote:
 

What is the best way to use asynchronous code in a scheduled job? I'm currently using the following code, but it seems to me that there should be a better way to do this than using "RunSynchronously()"

using EPiServer.PlugIn;
using EPiServer.Logging;
using J127T.PaymentGateway.Service;

namespace JamesTrustWF.Web.Plugins
{
    [ScheduledPlugIn(DisplayName = "Update Fund Balances",
    Description = "Update fund balances every week.",
    SortIndex = 1)]
    public class UpdateFundBalances
    {
        private static readonly ILogger Logger = LogManager.GetLogger();

        /// 
        /// Update fund balances
        /// 
        /// A status message that will be logged
        public static string Execute()
        {
            string msg;

            using (var fundService = new FundService())
            {
                try
                {
                    fundService.UpdateFundBalances().RunSynchronously();
                }
                catch (System.Exception ex)
                {
                    msg = "Error updating fund balances.";
                    Logger.Error(msg, ex);
                    return msg;
                 }
             }

             msg = "Updated fund balances.";
             Logger.Information(msg);
             return msg;
        }
    }
}


Edit: This code doesn't actually work, since it results in "System.InvalidOperationException: RunSynchronously may not be called on a task not bound to a delegate, such as the task returned from an asynchronous method." I could use other approaches to get the code to run synchronously, or add a synchronous version of the UpdateFundBalances() method, but that's not really the point.

#187960
Edited, Feb 07, 2018 11:07
Vote:
 

Call .Wait() instead, or .Result if the Task yields a result (and you are interested in that result).

#187963
Edited, Feb 07, 2018 13:10
Vote:
 

Call Wait() instead, or .Result if the Task yields a result (and you are interested in that result).

#187964
Feb 07, 2018 13:10
Vote:
 

That works, but I was wondering if there is any way to run the scheduled jobs asynchronously? This task takes about 3 minutes to complete, so having it block for that long does not seem ideal. I may be fundamentally misunderstanding how the scheduled jobs work - perhaps there would be no performance difference using async / await?

#187978
Feb 07, 2018 18:55
Vote:
 

Please use a bit advanced version (keep in mind exceptions that might occour once anync "comes" back):

public static class AsyncHelper
{
    private static readonly TaskFactory _myTaskFactory = new TaskFactory(CancellationToken.None,
                                                                         TaskCreationOptions.None,
                                                                         TaskContinuationOptions.None,
                                                                         TaskScheduler.Default);

    public static TResult RunSync<TResult>(Func<Task<TResult>> func)
    {
        return _myTaskFactory.StartNew(func)
                             .Unwrap()
                             .GetAwaiter()
                             .GetResult();
    }

    public static void RunSync(Func<Task> func)
    {
        _myTaskFactory.StartNew(func)
                      .Unwrap()
                      .GetAwaiter()
                      .GetResult();
    }
}

as to performance penalty - think case here (might be wrong) is that this thread will be occupied with idling while waiting for the results from async method. other scheduled jobs should run normally on scheduled basis..

#187980
Feb 07, 2018 20:59
This topic was created over six months ago and has been resolved. If you have a similar question, please create a new topic and refer to this one.