Revisiting Action Cable for notifications, 6 years later

I got a chance recently to take a Day of Learning and decided to try implementing Action Cable in Foreman.

In development environments, you may notice the web UI polls for notifications every 10 seconds:

16:53:12 rails.1   | 2026-02-13T16:53:12 [I|app|fa39da7b] Started GET "/notification_recipients" for 10.22.81.169 at 2026-02-13 16:53:12 -0500
16:53:12 rails.1   | 2026-02-13T16:53:12 [I|app|fa39da7b] Processing by NotificationRecipientsController#index as JSON
16:53:12 rails.1   | 2026-02-13T16:53:12 [D|not|fa39da7b] Cache Miss: notification, writing cache for notification-4
16:53:12 rails.1   | 2026-02-13T16:53:12 [D|not|fa39da7b] Expiring notification cache notification-4 in 3600 seconds
16:53:12 rails.1   | 2026-02-13T16:53:12 [D|app|fa39da7b] Body: {"notifications":[]}
16:53:12 rails.1   | 2026-02-13T16:53:12 [I|app|fa39da7b] Completed 200 OK in 11ms (Views: 0.1ms | ActiveRecord: 2.8ms | Allocations: 4157)

This eliminates* that polling in favor of a WebSocket connection that receives messages immediately. (well, I kept the polling as a fallback every 5 minutes instead of 10 seconds.)

Here is my proof-of-concept PR:

After taking the day to learn about and implement it, I found the discussion from a PR by @Ron_Lavi from around 6 years ago on Fixes #29628 - add action cable with redux channel by Ron-Lavi · Pull Request #7611 · theforeman/foreman · GitHub.

It seems the approach I took just happens to address the criticism at that time about being too generic (mine is limited to notifications only), but I’m also not sure what else has changed about our infrastructure since 2020. I don’t think we use passenger any more, for one.

I would welcome any feedback.

3 Likes

First reaction when I saw the title: yes please.

This is indeed the big change. We now only support Puma and I think it should work.

1 Like