vsivsi / meteor-job-collection

A persistent and reactive job queue for Meteor, supporting distributed workers that can run anywhere.
https://atmospherejs.com/vsivsi/job-collection
Other
388 stars 68 forks source link

Job: save and execute immediately #230

Open tankhuu opened 7 years ago

tankhuu commented 7 years ago

I want to define a job, which will be scheduled to run later but will run 1 time immediately after job created. I tried to use jc.readyJobs, but seems It didn't work, or I had misunderstanding. Please help: Here are my definition for job:

JC Definition

import {JobCollection} from 'meteor/vsivsi:job-collection';

// Jobs collections
const Jobs = new JobCollection('jobs');

JobCollection

{
        "_id" : "rFiWcjz2fTa6GqXpT",
        "runId" : null,
        "type" : "check Total Revenue",
        "data" : {
                "method" : "elastic",
        },
        "created" : ISODate("2017-04-18T08:10:15.949Z"),
        "priority" : 0,
        "retries" : 9007199254740992,
        "repeatRetries" : 9007199254740992,
        "retryWait" : 300000,
        "retried" : 0,
        "retryBackoff" : "constant",
        "retryUntil" : ISODate("275760-09-13T00:00:00Z"),
        "repeats" : 9007199254740991,
        "repeatWait" : {
                "schedules" : [
                        {
                                "t" : [
                                        29400
                                ]
                        }
                ],
                "exceptions" : [ ]
        },
        "repeated" : 1,
        "repeatUntil" : ISODate("275760-09-13T00:00:00Z"),
        "depends" : [ ],
        "resolved" : [ ],
        "status" : "waiting",
        "updated" : ISODate("2017-04-18T08:17:41.699Z"),
        "progress" : {
                "completed" : 0,
                "total" : 1,
                "percent" : 0
        },
        "log" : [
                {
                        "time" : ISODate("2017-04-18T08:10:15.949Z"),
                        "runId" : null,
                        "message" : "Rerunning job",
                        "level" : "info"
                },
                {
                        "time" : ISODate("2017-04-18T08:17:20.371Z"),
                        "runId" : null,
                        "message" : "Job Cancelled",
                        "level" : "warning"
                },
                {
                        "time" : ISODate("2017-04-18T08:17:41.699Z"),
                        "runId" : null,
                        "message" : "Job Restarted",
                        "level" : "info"
                }
        ],
        "after" : ISODate("2017-04-19T08:10:00.023Z")
}

Cancel, restart, ready operations

> Jobs.cancelJobs([ 'rFiWcjz2fTa6GqXpT' ])
true
> Jobs.restartJobs([ 'rFiWcjz2fTa6GqXpT' ])
true
> Jobs.readyJobs([ 'rFiWcjz2fTa6GqXpT' ])
false

I can cancel, restart the jobs, but can't make it ready.

vsivsi commented 7 years ago

The issue appears to be that the job is set to run: "after" : ISODate("2017-04-19T08:10:00.023Z")

Inferring from the log entries, that appears to be ~24 hours in the future from the time when you ran the test. So, running Jobs.readyJobs() will have no effect on this job because it won't be eligible to become ready until tomorrow.

You don't show the code that you used to actually create and schedule this job, so I don't know how it got that way. You can always force a job to become ready, even if it is not ready to run using either the time or force options to job.ready() or Jobs.readyJobs(). But unless you are manually overriding the job settings (as through a UI) that is not usually what you want to be doing.

tankhuu commented 7 years ago

Thank you for your reply. This is the function I used to create the job:

const createJob = (type, attributes, data) => {
  const
    {
      depends = [],
      priority = 'normal',
      retry = {},
      repeat = {
        schedule: later.parse.text('every 5 minutes')
      },
      delay = 0,
      after = new Date()
    } = attributes,
    {
      // API information
    } = data
    ;

  const job = new Job(Jobs, type, data);
  job
    .depends(depends)
    .priority(priority)
    .retry(retry)
    .repeat(repeat)
    .delay(delay)
    .after(after)
    .save()
  ;

  Jobs.processJobs(type, Workers.execute);

  return {};
};

createJob('test_job', {priority: 'normal', repeat: {schedule: later.parse.text('at 3:00 am')}}, {});

According to your reply, then I can make it run immediately by adding job.ready() after I saved the job, right? the creating job could be like this:

const createJob = (type, attributes, data) => {
  const
    {
      depends = [],
      priority = 'normal',
      retry = {},
      repeat = {
        schedule: later.parse.text('every 5 minutes')
      },
      delay = 0,
      after = new Date()
    } = attributes,
    {
      // API information
    } = data
    ;

  const job = new Job(Jobs, type, data);
  job
    .depends(depends)
    .priority(priority)
    .retry(retry)
    .repeat(repeat)
    .delay(delay)
    .after(after)
    .save()
    .ready()
  ;

  Jobs.processJobs(type, Workers.execute);

  return {};
};
tankhuu commented 7 years ago

When I set the schedule is 'at 3:00 am' the "after" : ISODate("2017-04-21T03:00:00Z") will always like that, even when I set job.after(new Date()) before job.save(). Then how can I make it run immediately after created?

vsivsi commented 7 years ago

Hi, If you want it to run immediately, and then repeat after some delay, dont use delay() or after(). Those settings only affect the first run (and if you use both, only the second one will apply, as they are just different ways of setting the same thing).

To set the delay for the second (and all subsequent) runs you should use either the wait: or schedule: options on job.repeat(). Using schedule is actually much more powerful, in that you use later.js to set up an arbitrarily complicated schedule instead of a simple repeat after delay.

Hope that helps.