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

Callbacks for app lifecycle? #2915

Closed
mperham opened this issue Aug 25, 2022 · 9 comments · Fixed by #2917
Closed

Callbacks for app lifecycle? #2915

mperham opened this issue Aug 25, 2022 · 9 comments · Fixed by #2917
Labels

Comments

@mperham
Copy link

mperham commented Aug 25, 2022

Hi, I'm wondering if puma has an API for applications to start and stop services that run within a puma process on start and stop. For example, Sidekiq has its on(event) API so that services can run inside each Sidekiq process:

Sidekiq.configure_server do |config|
  config.on(:startup) do
    t = Thread.new do
      loop do
        puts Time.now
        sleep 1
      end
    end
    config.on(:shutdown) do
      t.raise Interrupt
    end
  end
end

I'm planning on adding support for Sidekiq running natively within other processes but the other process needs to offer something like this API so Sidekiq can be started and stopped "cleanly". What would you recommend here? The only clean shutdown option I can find today is at_exit which is less than ideal.

@MSP-Greg
Copy link
Member

MSP-Greg commented Aug 26, 2022

If one is using Puma in clustered mode, there are on_worker_boot, on_worker_fork, & on_worker_shutdown.

See https://msp-greg.github.io/puma/Puma/DSL.html#on_worker_boot-instance_method

Nate may have some suggestions/thoughts...

@nateberkopec
Copy link
Member

What Greg said - we don't yet have equivalents yet for single mode: #2709

@mperham
Copy link
Author

mperham commented Aug 26, 2022

Ok, worker_boot and worker_shutdown will work with one caveat, there's no way for the two callbacks to share data except thru global variables. How do I start something in boot and get a handle to it in shutdown without creating this ugly global variable?

on_worker_boot do
  $sidekiq = launcher = Sidekiq.configure_embed do |config|
    config.queues = %w[critical default low]
  end
  launcher.run
end

on_worker_shutdown do
  $sidekiq&.stop
end

Could puma pass an argument into those blocks which we can use to register components?

@MSP-Greg
Copy link
Member

So, lets say one has four workers. Is it okay with you that the shared data is unique to each worker?

@mperham
Copy link
Author

mperham commented Aug 26, 2022

Yes, that's the intent. Since Sidekiq is threaded, we want to launch threads in each worker in order to get good utilization across cores.

@MSP-Greg
Copy link
Member

I think I've got a 'non-breaking change' idea. Maybe tomorrow or Sunday.

Puma will hold a Hash reference and pass it into the blocks?

@schuetzm
Copy link

How do I start something in boot and get a handle to it in shutdown without creating this ugly global variable?

Simply declare a local variable outside the block:

sidekiq = nil

on_worker_boot do
  sidekiq = Sidekiq.configure_embed do |config|
    config.queues = %w[critical default low]
  end
  sidekiq.run
end

on_worker_shutdown do
  sidekiq&.stop
end

@MSP-Greg
Copy link
Member

@schuetzm I think that will be shared by workers? I've got a patch for it, soon to create a test PR...

@MSP-Greg
Copy link
Member

@mperham

Using PR #2917, I believe the following should work:

on_worker_boot(:sidekiq) do |idx, data|
    data[:any_key] = launcher = Sidekiq.configure_embed do |config|
    config.queues = %w[critical default low]
  end
  launcher.run
end

on_worker_shutdown(:sidekiq) do |idx, data|
  data[:any_key]&.stop
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants