HangfireIO / Hangfire

An easy way to perform background job processing in .NET and .NET Core applications. No Windows Service or separate process required
https://www.hangfire.io
Other
9.33k stars 1.69k forks source link

Wait for response from webapi in background job #1408

Open Bryankarlsson opened 5 years ago

Bryankarlsson commented 5 years ago

I have a hangfire app running. Hangfire is responsible to start multiple different api services via recurring jobs:

[HttpPost]
public void Post([FromForm] Model value)
{
    var apiUrl = value.ApiUrl; // http://api.com/start/1
    var interval = value.Interval;

    RecurringJob.AddOrUpdate(value.ApiName, () => RunInBackground(apiUrl), Cron.MinuteInterval(value.Interval));
    var api = JobStorage.Current.GetMonitoringApi();
}

[DisableConcurrentExecutionWithParametersAttribute(timeoutInSeconds: 10 * 60)]
[AutomaticRetry(Attempts = 0)]
public async Task<bool> RunInBackground(string Url)
{   
    using (HttpClient httpClient = new HttpClient())
    {
        var response = await httpClient.GetAsync(Url);
        httpClient.DefaultRequestHeaders.Accept.Clear();
        httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

        var responseFromApi = await response.Content.ReadAsStringAsync();

        return true;
    }

}

The thing I want to accomplish Is to wait for the responses from the api:s, before starting the job again. How can I do that?

Anyone who can help me?

odinserj commented 5 years ago

Check the SkipWhenPreviousJobIsRunningAttribute filter and always use a cached HttpClient instance – https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/.

Bryankarlsson commented 5 years ago

Check the SkipWhenPreviousJobIsRunningAttribute filter and always use a cached HttpClient instance – https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/.

How should I use that filter on my RunInBackground-method? Can you give me a example?

odinserj commented 5 years ago
[SkipWhenPreviousJobIsRunning]
[DisableConcurrentExecutionWithParametersAttribute(timeoutInSeconds: 10 * 60)]
[AutomaticRetry(Attempts = 0)]
public async Task<bool> RunInBackground(string Url) ...
Bryankarlsson commented 5 years ago

Thanks.

One question: My list of Processing jobs is ingreasing? Should they not be succeeded? bild

odinserj commented 5 years ago

Looks like SkipWhenPreviousJobIsRunning filter is triggered after the DisableConcurrentExecutionWithParameters one, and we need the vice versa. Try to set the following ordering in your jobs:

[SkipWhenPreviousJobIsRunning(Order = 5)]
[DisableConcurrentExecutionWithParametersAttribute(timeoutInSeconds: 10 * 60, Order = 10)]
Bryankarlsson commented 5 years ago

Thanks for your help.

When I try to add the Order value on SkipWhenPreviousJobIsRunning, I get the following error: The type or namespace name Order could not be found..

odinserj commented 5 years ago

Don't know what's the problem, it should work just fine:

image

Bryankarlsson commented 5 years ago

Im doing like this: bild

Herer is my SkipWhenPreviousJobIsRunnig class:

 public class SkipWhenPreviousJobIsRunning : System.Attribute
    {
        public void OnCreating(CreatingContext context)
        {
            var connection = context.Connection as JobStorageConnection;

            // We can't handle old storages
            if (connection == null) return;

            // We should run this filter only for background jobs based on 
            // recurring ones
            if (!context.Parameters.ContainsKey("RecurringJobId")) return;

            var recurringJobId = context.Parameters["RecurringJobId"] as string;

            // RecurringJobId is malformed. This should not happen, but anyway.
            if (String.IsNullOrWhiteSpace(recurringJobId)) return;

            var running = connection.GetValueFromHash($"recurring-job:{recurringJobId}", "Running");
            if ("yes".Equals(running, StringComparison.OrdinalIgnoreCase))
            {
                context.Canceled = true;
            }
        }

        public void OnCreated(CreatedContext filterContext)
        {
        }

        public void OnStateApplied(ApplyStateContext context, IWriteOnlyTransaction transaction)
        {
            if (context.NewState is EnqueuedState)
            {
                var recurringJobId = JobHelper.FromJson<string>(context.Connection.GetJobParameter(context.BackgroundJob.Id, "RecurringJobId"));
                if (String.IsNullOrWhiteSpace(recurringJobId)) return;

                transaction.SetRangeInHash(
                    $"recurring-job:{recurringJobId}",
                    new[] { new KeyValuePair<string, string>("Running", "yes") });
            }
            else if (context.NewState.IsFinal)
            {
                var recurringJobId = JobHelper.FromJson<string>(context.Connection.GetJobParameter(context.BackgroundJob.Id, "RecurringJobId"));
                if (String.IsNullOrWhiteSpace(recurringJobId)) return;

                transaction.SetRangeInHash(
                    $"recurring-job:{recurringJobId}",
                    new[] { new KeyValuePair<string, string>("Running", "no") });
            }
        }

        public void OnStateUnapplied(ApplyStateContext context, IWriteOnlyTransaction transaction)
        {
        }
    }