Class: CrmNavbarRefreshWorker

Inherits:
Object
  • Object
show all
Includes:
Sidekiq::Worker
Defined in:
app/workers/crm_navbar_refresh_worker.rb

Overview

Renders and broadcasts one navbar fragment for one user.

Coalescing: a burst of N events all asking us to refresh the same
(user, badge) collapses into one job. The first call writes a "pending"
Redis key with a 2s TTL and schedules the job to run +2s later; subsequent
calls within that window see the key and short-circuit. The job clears the
key when it runs, so the next event after the window opens a fresh window.

This means at most one broadcast per (user, badge) per 2 seconds — bounded
load even during a flood of inbound SMS / voicemails / emails.

Constant Summary collapse

COALESCE_WINDOW =
2.seconds
PENDING_KEY =
'crm_navbar_pending'

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.pending_key(user_id, badge) ⇒ Object



40
41
42
# File 'app/workers/crm_navbar_refresh_worker.rb', line 40

def pending_key(user_id, badge)
  "#{PENDING_KEY}:#{user_id}:#{badge}"
end

.schedule(user_id:, badge:) ⇒ Object

Public entry point. Returns true if a refresh was scheduled, false if
an existing pending refresh will already cover this event.



28
29
30
31
32
33
34
35
36
37
38
# File 'app/workers/crm_navbar_refresh_worker.rb', line 28

def schedule(user_id:, badge:)
  key = pending_key(user_id, badge)
  acquired = Sidekiq.redis do |r|
    # SET key 1 NX EX 2 — atomic "set if absent with TTL".
    r.set(key, '1', nx: true, ex: COALESCE_WINDOW.to_i)
  end
  return false unless acquired

  perform_in(COALESCE_WINDOW, user_id, badge.to_s)
  true
end

Instance Method Details

#perform(user_id, badge) ⇒ Object



45
46
47
48
49
50
51
52
53
# File 'app/workers/crm_navbar_refresh_worker.rb', line 45

def perform(user_id, badge)
  Sidekiq.redis { |r| r.del(self.class.pending_key(user_id, badge)) }

  user = Employee.find_by(id: user_id)
  return unless user
  return unless CrmNavbarBroadcaster::BADGES.key?(badge.to_sym)

  CrmNavbarBroadcaster.refresh(user, badge: badge.to_sym)
end