Stopping a running scheduled task in shopware6 - shopware6

I would like to know how to stop a running scheduled task in shopware 6.
We have some huge integrations and they can be running for several hours updating +500K products.
This I would like to be able to stop if I see that the job is not running as expected.

Look in the table scheduled_task for the task you want to deactivate and change the value of the column status to inactive.
Programmatically:
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('name', 'name_of_task'));
// scheduled_task.repository
$taskId = $this->scheduledTaskRepository->searchIds($criteria, $context)->firstId();
$this->scheduledTaskRepository->update([
[
'id' => $taskId,
'status' => ScheduledTaskDefinition::STATUS_INACTIVE,
],
], $context);

Related

Static Hangfire RecurringJob methods in LINQPad are not behaving

I have a script in LINQPad that looks like this:
var serverMode = EnvironmentType.EWPROD;
var jobToSchedule = JobType.ABC;
var hangfireCs = GetConnectionString(serverMode);
JobStorage.Current = new SqlServerStorage(hangfireCs);
Action<string, string, XElement> createOrReplaceJob =
(jobName, cronExpression, inputPackage) =>
{
RecurringJob.RemoveIfExists(jobName);
RecurringJob.AddOrUpdate(
jobName,
() => new BTR.Evolution.Hangfire.Schedulers.JobInvoker().Invoke(
jobName,
inputPackage,
null,
JobCancellationToken.Null),
cronExpression, TimeZoneInfo.Local);
};
// psuedo code to prepare inputPackage for client ABC...
createOrReplaceJob("ABC.CustomReport.SurveyResults", "0 2 * * *", inputPackage);
JobStorage.Current.GetConnection().GetRecurringJobs().Where( j => j.Id.StartsWith( jobToSchedule.ToString() ) ).Dump( "Scheduled Jobs" );
I have to schedule in both QA and PROD. To do that, I toggle the serverMode variable and run it once for EWPROD and once for EWQA. This all worked fine until recently, and I don't know exactly when it changed unfortunately because I don't always have to run in both environments.
I did purchase/install LINQPad 7 two days ago to look at some C# 10 features and I'm not sure if that affected it.
But here is the problem/flow:
Run it for EWQA and everything works.
Run it for EWPROD and the script (Hangfire components) seem to run in a mix of QA and PROD.
When I'm running it the 'second time' in EWPROD I've confirmed:
The hangfireCs (connection string) is right (pointing to PROD) and it is assigned to JobStorage.Current
The query at the end of the script, JobStorage.Current.GetConnection().GetRecurringJobs() uses the right connection.
The RecurringJob.* methods inside the createOrReplaceJob Action use the connection from the previous run (i.e. EWQA). If I monitor my QA Hangfire db, I see the job removed and added.
Temporary workaround:
Run it for EWQA and everything works.
Restart LINQPad or use 'Cancel and Reset All Queries' method
Run it for EWPROD and now everything works.
So I'm at a loss of where the issue might lie. I feel like my upgrade/install of LINQPad7 might be causing problems, but I'm not sure if there is a different way to make the RecurringJob.* static methods use the 'updated' connection string.
Any ideas on why the restart or reset is now needed?
LINQPad - 5.44.02
Hangfire.Core - 1.7.17
Hangfire.SqlServer - 1.7.17
This is caused by your script (or a library that you call) caching something statically, and not cleaning up between executions.
Either clear/dispose objects when you're done (e.g., JobStorage.Current?) or tell LINQPad not to re-use the process between executions, by adding Util.NewProcess=true; to your script.

How to fetch the current run status (i.e. success or failure) of all metronome jobs?

We are using metronome, and we want to create a dashboard for our jobs scheduled by it against its rest API.
Alas, the job endpoint
/v1/jobs
does not contain the last state, i.e. success or failure, but only its configuration.
Googling on how to get the history of a job, I found out that I can query the job history through embed=history GET parameter for each jobId.
I could now combine fetching the id list so that I could then fetch each job's history through:
/v1/jobs/{job_id}?embed=history
Yet this includes all the runs and also requires us to fetch each job individually.
Is there a way to get the metronome job status without querying all the jobs one by one?
You can click on each GET or POST endpoint on the official docs to see if it supports additional query params.
The endpoint for jobs indeed supports historic data
As you can see you can use embed=history or embed=historySummary, for your use-case embed=historySummary is better suited as it only contains the timestamps of the last run in this form and is less expensive and time-consuming:
[
{
"id": "your_job_id",
"historySummary": {
"failureCount": 6,
"lastFailureAt": "2018-01-26T12:18:46.406+0000",
"lastSuccessAt": "2018-04-19T13:50:14.132+0000",
"successCount": 226
},
...
},
...
]
You can compare those dates to figure out if the last run was successful. Yet keep in mind that lastFailureAt and lastSuccessAt might be null as a job might have been never run in the first place:
{
"id": "job-that-never-ran",
"labels": {},
"run": {
...
}
"historySummary": {
"successCount": 0,
"failureCount": 0,
"lastSuccessAt": null,
"lastFailureAt": null
}
},

Hangfire Job timout

I have certain jobs that appear to be 'Hung' in hangfire and may run for hours but aren't actually doing anything. Is there a way for Hangfire to kill a job if it runs longer than a certain amount to time?
I'm running the latest version of Hangfire on SQL server.
In your job creation (doesn't matter if it's a recurring or a single background job) call, pass in an extra param of type "IJobCancellationToken" to your job method like this,
public static void Method1(string param1, IJobCancellationToken token) { }
When you create your job, create it with a null IJobCancellationToken token value and save the jobId. Have another recurring job that polls these jobs and simply call BackgroundJob.Delete(jobId) when it exceeds your desired time limit. This will clear the job from hangfire and also kill the process on your server.
Reference: https://discuss.hangfire.io/t/how-to-cancel-a-job/872
Yes you can do this, you'll want to set the FetchNextJobTimeout at startup. By setting FetchNextJobTimeout, you can control how long a job can run for before Hangfire starts executing it again on another thread.
services.AddHangfire(config => {
config.UseMemoryStorage(new MemoryStorageOptions { FetchNextJobTimeout = TimeSpan.FromHours(24) });
});

Hangfire: How to enqueue a job conditionally

I am using Hangfire to trigger a database retrieval operation as a background job.
This operation is only supposed to happen once, and can be triggered in multiple ways. (for example, in the UI whenever a user drags and drops a tool, I need to fire that job in the background. But if another tool is dragged and dropped, I don't want to fire the background job as it's already prefetched from the database).
This is what my code looks like now:
var jobId = BackgroundJob.Enqueue<BackgroundModelHelper>( (x) => x.PreFetchBillingByTimePeriods(organizationId) );
What I want is some kind of check before I execute above statement, to find if a background job has already been fired; if yes, then do not fire another and if not, then enqueue this .
for example:
bool prefetchIsFired = false;
// find out if a background job has already been fired. If yes, set prefetchIsFired to true.
if (!prefetchIsFired)
var jobId = BackgroundJob.Enqueue<BackgroundModelHelper>( (x) => x.PreFetchBillingByTimePeriods(organizationId, null) );
You can use a filter (DisableMultipleQueuedItemsFilter) on your job method like here : https://discuss.hangfire.io/t/how-do-i-prevent-creation-of-duplicate-jobs/1222/4

Filter Hangfire succeded job list

Is there a way to have a job not appear in the Succeeded Job list?
I currently have 2 recurring jobs set up as follows:
RecurringJob.AddOrUpdate("myQuickJob", () => CallRemoteService(quickCheckUrl)), Cron.Minutely());
RecurringJob.AddOrUpdate("myDailyJob", () => CallRemoteService(dailyJobUrl)), Cron.Daily(0));
One is a daily scheduled job the other is a quick ping job. I am really only interested in the results (success/fail) of the daily job and not the quick job.
As you can imagine the resuls of the quick job very quickly fill up the Job list with hundreds of succeeded calls of which I am not interested and it gets hard to isolate the daily jobs.
So, is there a way to:
Turn off the job log/display of the quick job
Have the name of the job show up in the list.
My job listing only shows all entries like:
#238 Startup.CallRemoteService 7.234s 13 minutes ago
#237 Startup.CallRemoteService 7.424s 23 minutes ago
so I can't distinguish between the myQuickJob and the myDailyJob. Can the Job name be changed in the listing so I see myDailyJob instead of Startup.CallRemoteService ?
ta
First of all, regarding your second problem the answer is quite easy: use a proxy method as below
RecurringJob.AddOrUpdate(
"myQuickJob",
() => CallRemoteServiceQuickCheck(quickCheckUrl)), Cron.Minutely());
// ^^^^^^^^^^
RecurringJob.AddOrUpdate(
"myDailyJob",
() => CallRemoteService(dailyJobUrl)), Cron.Daily(0));
[...]
public void CallRemoteServiceQuickCheck(Uri url) {
CallRemoteService(url));
}
and your log will look like
#238 Startup.CallRemoteServiceQuickCheck 7.234s 13 minutes ago
#237 Startup.CallRemoteService 7.424s 23 minutes ago
Now for your other problem, it's more tricky.
I thinkthe easiest would be to add a new menu item "Filtered Succeded" in the left pane of the dashboard as follows where you init your app:
Hangfire.Dashboard.JobsSidebarMenu.Items.Add(
(rp) => {
var filteredSuccededUrl = "[your_url_here]";
return new Hangfire.Dashboard.MenuItem("FilteredSucceded",
filteredSuccededUrl); });
You can have this point to the url of your choice. Not ideal, but you have the source code of the succeeded page you can use to create your new page here.