# Scheduling jobs from a plugin

**URL:** <https://meta.discourse.org/t/scheduling-jobs-from-a-plugin/40238>\
**Category:** Development\
**Created:** [February 26, 2016, 7:01pm UTC](https://meta.discourse.org/t/scheduling-jobs-from-a-plugin/40238 "2016-02-26T19:01:09Z")\
**Posts on this page:** 1\
**Showing post:** 10

<div class="post-metadata">

**Author:** ![bletch](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/bletch/32/69088_2.png) [@bletch](https://meta.discourse.org/u/bletch)\
**Post date:** [October 27, 2018, 9:42am UTC](https://meta.discourse.org/t/scheduling-jobs-from-a-plugin/40238/10 "2018-10-27T09:42:35Z")

</div>

OK for posterity, those that follow and my ageing memory (in case I need to remember how I did it)…

The problem was that the Wizard plugin was timing out because I was trying to create up to 77 topics synchronously. I needed to enqueue a series of jobs that would create topics asynchronously so that I could return control to the Wizard plugin to stop it timing out.

In looking at the various `Job` class definitions that I found in the source, I couldn’t figure out how to instantiate the class and put it on a sidekiq queue.

After some digging, this appears to come from `Jobs.enqueue(:job_name, args)`. (I believe there are variations of this that schedule jobs and enqueue repeating jobs.

Anyway, the steps I took to defer the creation of topics…

### Create the job that will create the topics

It appears to be a convention with plugins to create a `plugin-name\jobs` directory and inside this folder, I created a Ruby script called `deferred_topic_creation.rb`. It looks like this…

```ruby
# school-points\jobs\deferred_topic_creation.rb
module Jobs
  class DeferredTopicCreation < Jobs::Base
    def execute(args)
      creator_user_id = args[:creator_user_id]
      custom_fields = {
        event_start: args[:event_start],
        event_end: args[:event_end]
      }

      creator_user = User.find(creator_user_id) || User.find(Discourse::SYSTEM_USER_ID)

      post_creator = PostCreator.new(
        creator_user,
        args.except!(:creator_user_id, :event_start, :event_end)
      )
      post = post_creator.create

      topic = Topic.find(post.topic_id)
      topic.custom_fields = custom_fields
      topic.save!
    end
  end
end

```

The code you want to execute when sidekiq finally processes the jobs seems to go inside the `execute` method, and, at least with an ordinary job (not scheduled or repeated) it is simply passed the `args` as a hash as the first parameter.

Gotcha! In keeping with other queueing systems I’ve used (in Python), you can’t pass Discourse / Rails objects through to the job in that `args` hash. If you do, the object is just serialised as a string. I don’t know how to instantiate the object from the string so my solution was to pass IDs of any discourse objects I needed (the user that would create the topics in my case) and then to `.find()` the object in the job `execute` method.

### `load` the job code in your plugin - inside the `after_initialize do` block like so

```ruby
after_initialize do
    .
    .
    .
    load File.expand_path('../jobs/deferred_topic_creation.rb', __FILE__ )
    .
    .
    .

```

I don’t know if where it is placed in the block is important but the path must resolve to our job definition in the `jobs` directory.

### Enqueue the jobs to create the topics

With that setup in place, you are then able to enqueue the job using a command like this

```ruby
opts = {
  title: title,
  raw: content,
  category: child_category[:id],
  creator_user_id: creator_user_id,
  event_start: event_start.to_time.to_i,
  event_end: event_end.to_time.to_i
}
Jobs.enqueue(:deferred_topic_creation, opts)

```

Note that the name of the job is passed as a symbol here.

In development mode remember to stop your server and kill sidekiq before deleting the `tmp` directory contents and starting the server and sidekiq again.

---

_[View the full topic](https://meta.discourse.org/t/scheduling-jobs-from-a-plugin/40238)._
