Rails ActiveJob and SSE: How to Update Page When An API Call is Finished

577 views Asked by At

I am planning to use SSE to update a page that shows Stripe subscription details.

Basically it goes as follows:

  1. load subscription detail page
  2. use an ActiveJob job to request subscription details from Stripe API
  3. when task is finished, use SSE to notify that client (the subscription page) that an update is to be made to the page
  4. perform the update via javascript

I have code setup for steps 1 and 2 and 4, however, I do not know how to perform #3.

One of the problems that I see is that an ActiveJob indeed has an after_perform callback, but the SSE built in Rails resides on the controller (ActionController::Live::SSE). I do not know how to do something in the SSE controller on the after_perform callback.

Googling, I found out a potential solution:

  1. Use a Sidekiq plugin to be able to tell when a task is finished.
  2. Use PostgreSQL NOTIFY / LISTEN

I don't know what goes after that, like how would the SSE controller know that the task is performed.

Other Notes:

I am using Brandon Hilkert's Sucker Punch gem for background processing: https://github.com/brandonhilkert/sucker_punch

I would also like a solution that will not force me to stick with PostgreSQL-exclusive code. However, I do not mind if that's the only approach that works.

I also posted a Sidekiq solution in case I can't do it with sucker_punch and would have to switch to Sidekiq.

Any ideas?

Thanks!

1

There are 1 answers

1
Luka Domitrovič On

Action Cable in Rails 5 is just build for this type of features. https://github.com/rails/rails/tree/master/actioncable

Action Cable brings web sockets to rails, which means persisted connection between client and server. You can perform actions from client (javascript/coffescript) and push json or even html partial updates back to the client.The best sense of how Action Cable works you will get from dhh tutorial https://www.youtube.com/watch?v=n0WUjGkDFS0

Generate new channel with rails g channel and set a scope of broadcast

def subscribed
  stream_from "subscription_#{current_user.id}"
end

In your case steps 1 and 2 stays the same. On the end of the step 3. I would add ActionCable.server.broadcast "subscription_#{current_user.id}", status: payment_status. Step 4. update state on client as you wanted to do.