Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use async_server as default execution mode in Development environment #139

Closed
multiplegeorges opened this issue Sep 17, 2020 · 9 comments · Fixed by #343
Closed

Use async_server as default execution mode in Development environment #139

multiplegeorges opened this issue Sep 17, 2020 · 9 comments · Fixed by #343

Comments

@multiplegeorges
Copy link
Contributor

multiplegeorges commented Sep 17, 2020

Hi @bensheldon

In development mode, good_job runs :inline, but seems to ignore the scheduled_at attribute and executes the job immediately. This makes sense, but was somewhat unexpected and I had to refer to the docs to figure it out.

I expected it to run more akin to an async, in-process job, but still respect the scheduled_at.

What happened

I had called MyJob.set(wait: 5.seconds).perform_later and the job executed immediately.

This created a job record in a seemingly impossible (or at least undesirable) state:

pry(main)> GoodJob::Job.all
  GoodJob::Job Load (0.6ms)  SELECT "good_jobs".* FROM "good_jobs"
=> [#<GoodJob::Job:0x00007fda65bd1270
  id: "53ff8466-0956-4023-9ae2-dbd80f8df3f6",
  queue_name: "default",
  priority: 0,
  serialized_params:
   {"job_id"=>"20cebbf0-b2c3-4f48-a8d3-00cb643afe06",
    "locale"=>"en",
    "priority"=>nil,
    "timezone"=>"UTC",
    "arguments"=>[],
    "job_class"=>"MyJob",
    "executions"=>0,
    "queue_name"=>"default",
    "enqueued_at"=>"2020-09-16T21:47:52Z",
    "provider_job_id"=>nil,
    "exception_executions"=>{}},
  scheduled_at: Wed, 16 Sep 2020 21:47:57 UTC +00:00,
  performed_at: Wed, 16 Sep 2020 21:47:52 UTC +00:00,
  finished_at: Wed, 16 Sep 2020 21:47:53 UTC +00:00,
  error: nil,
  created_at: Wed, 16 Sep 2020 21:47:52 UTC +00:00,
  updated_at: Wed, 16 Sep 2020 21:47:53 UTC +00:00>]

This job has performed_at set earlier than scheduled_at.

What I expected

That the job would enqueue, wait 5 seconds, and execute async, but in-process, much like the default Rails async job behaviour.

This matches what will happen in production more closely and avoids records in impossible states.

Thoughts?

@morgoth
Copy link
Collaborator

morgoth commented Sep 17, 2020

I believe this is by design. For your expected behavior you should use :async mode as stated in the readme https://github.com/bensheldon/good_job#adapter-options

Since it works in the same way as ActiveJob inline mode, is there a need for it in this gem @bensheldon ?

@multiplegeorges
Copy link
Contributor Author

Yeah, async is probably the correct option for my expectation.

Perhaps this ticket is more about what the default should be in dev mode?
Async would most closely match production and avoid the inconsistent record issue I raised.

@jrochkind
Copy link
Contributor

What do other systems with ActiveJob adapters do? Like sidekiq or resque? I think what is appropriate is whatever they do.

Is the "default in dev mode" really even up to us, or up to ActiveJob? It may be different in different versions of Rails, I seem to recall at one point Rails changed from :inline as default in dev mode to :async as default in dev mode.

@bensheldon
Copy link
Owner

Thanks everyone for the discussion!

I'm not quite confident of a strong path forward, but let me share my thinking today:

  • I desire an opinionated Adapter that has good defaults across Dev, Test and Production. This is configurable within GoodJob:
    # Like {#execution_mode}, but takes the current Rails environment into
    # account (e.g. in the +test+ environment, it falls back to +:inline+).
    # @return [Symbol]
    def rails_execution_mode
    if execution_mode(default: nil)
    execution_mode
    elsif Rails.env.development?
    :inline
    elsif Rails.env.test?
    :inline
    else
    :external
    end
    end
  • I expect the Development environment to have the ability (and default) to perform jobs without running an external process. This is differentiator of GoodJob compared to other adapters I've worked with.
  • I think the GoodJob Async adapter is also a differentiator of GoodJob... but I find it currently annoying/distracting as a Development default because of the polling mechanism cluttering up the debug logs. There is some fruitful ideas like Why poll when using LISTEN/NOTIFY? #90 (comment) that, while I'm still not sure could do away with polling entirely, might allow dropping it back to something much less frequent, > 1 minute. Not cluttering the debug logs is the reservation I have for not making :async be the default development execution mode.

@oyeanuj
Copy link

oyeanuj commented Sep 22, 2020

In development, GoodJob executes jobs immediately

I'm also running into some confusion with what I believe to be a related issue. It seems as part of this inline behavior, it also seems to be ignoring set(wait: 3.days) option as well.

@bensheldon Is this expected? And if not, let me know if you'd like me to create a new issue here.

@bensheldon
Copy link
Owner

@oyeanuj yes, that is expected behavior. From readme:

:inline executes jobs immediately in whatever process queued them (usually the web server process).

Arguably the emphasis should be on immediately in that sentence.

Practically speaking, I'd love your feedback about the experience of running the :async mode in development, which does allow using delays, e.g.set(wait: 1.day). I've written above about my own experience/feelings, but I'm willing to be wrong.

# config/environments/development.rb
config.active_job.queue_adapter = GoodJob::Adapter.new(execution_mode: :async)

@bensheldon
Copy link
Owner

Update on this. I expect the next release (~v1.8.0)of GoodJob to set async excecution mode as the default in the development environment.

This is the configuration I'm expecting to default to, that works in the current release (v1.7.0):

# config/environment/development.rb

config.active_job.queue_adapter = :good_job

if ENV['GOOD_JOB_EXECUTION_MODE']
  config.good_job.execution_mode = ENV['GOOD_JOB_EXECUTION_MODE'].to_sym
elsif Rails.const_defined?("Server")
  config.good_job.execution_mode = :async
elsif Rails.const_defined?("Console")
  config.good_job.execution_mode = :external
end

config.good_job.poll_interval = 60 # seconds

@bensheldon
Copy link
Owner

Just wanted to update this issue that async has not yet been made the development default. I ran into some complexities, and now the intention is to set async_server (#230) in development once I feel confident in it.

@bensheldon
Copy link
Owner

bensheldon commented Jul 25, 2021

For #307:

  • Set default execution mode in Development environment to async_server
  • Disable polling in Development environment

@bensheldon bensheldon changed the title In dev, :inline executes scheduled jobs immediately. Should it? Use async_server as default execution mode in Development environment Jul 25, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants