Module: FlowChat::GatewayAsyncSupport
- Included in:
- Http::Gateway::Simple, Intercom::Gateway::IntercomApi, Meta::MessagingGateway, Telegram::Gateway::BotApi, Ussd::Gateway::Nalo, Whatsapp::Gateway::CloudApi
- Defined in:
- lib/flow_chat/gateway_async_support.rb
Overview
Concern for gateways to support async background processing Mix this into gateway classes to enable async detection and job enqueueing
Instance Attribute Summary collapse
-
#context ⇒ Object
readonly
Returns the value of attribute context.
-
#controller ⇒ Object
readonly
Returns the value of attribute controller.
Instance Method Summary collapse
-
#async_supported? ⇒ Boolean
Check if gateway supports async processing Override in gateways that don't support async (e.g., USSD).
-
#enqueue_async_job ⇒ Object
Enqueue background job with serialized request context Returns true if job was enqueued, false otherwise.
-
#extract_body_for_background(request) ⇒ Object
Extract request body for background processing Override in gateways that need the request body.
-
#extract_headers_for_background(request) ⇒ Object
Extract serializable headers needed for background processing Override in gateways that need additional headers.
-
#extract_host(request) ⇒ Object
Extract host from request for URL boundary support.
-
#extract_path(request) ⇒ Object
Extract path from request for URL boundary support.
-
#extract_remote_ip(request) ⇒ Object
Extract remote IP from request.
-
#in_background? ⇒ Boolean
Detect if we're currently in background mode.
-
#should_enqueue_async? ⇒ Boolean
Check if async processing should be used Returns true if: - Not already in background mode - Processor has async enabled - Gateway supports async.
-
#side_events_already_published? ⇒ Boolean
Whether an earlier pass already announced this delivery's side events, which is the case only for a job the gem enqueued after publishing them itself.
Instance Attribute Details
#context ⇒ Object (readonly)
Returns the value of attribute context.
7 8 9 |
# File 'lib/flow_chat/gateway_async_support.rb', line 7 def context @context end |
#controller ⇒ Object (readonly)
Returns the value of attribute controller.
7 8 9 |
# File 'lib/flow_chat/gateway_async_support.rb', line 7 def controller @controller end |
Instance Method Details
#async_supported? ⇒ Boolean
Check if gateway supports async processing Override in gateways that don't support async (e.g., USSD)
11 12 13 |
# File 'lib/flow_chat/gateway_async_support.rb', line 11 def async_supported? true end |
#enqueue_async_job ⇒ Object
Enqueue background job with serialized request context Returns true if job was enqueued, false otherwise
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/flow_chat/gateway_async_support.rb', line 47 def enqueue_async_job return false unless should_enqueue_async? processor = @context["processor"] FlowChat.logger.info { "#{self.class.name}: Async enabled - enqueuing background job" } # Serialize request data for BackgroundController # # side_events_published records that this pass has already announced the # delivery's side events, so the job it is about to enqueue does not # announce them a second time. It rides in the request context rather # than in params, where a platform's own webhook fields live. request_data = { params: @controller.request.params.to_h, method: @controller.request.method, headers: extract_headers_for_background(@controller.request), host: extract_host(@controller.request), path: extract_path(@controller.request), body: extract_body_for_background(@controller.request), remote_ip: extract_remote_ip(@controller.request), side_events_published: true } # Enqueue user's job with request context and job params processor.async_job_class.perform_later( request_context: request_data, **processor.async_job_params ) FlowChat.logger.info { "#{self.class.name}: Background job enqueued successfully" } true end |
#extract_body_for_background(request) ⇒ Object
Extract request body for background processing Override in gateways that need the request body
107 108 109 110 111 112 113 114 115 |
# File 'lib/flow_chat/gateway_async_support.rb', line 107 def extract_body_for_background(request) return nil unless request.body body_content = request.body.read request.body.rewind # Reset for subsequent reads body_content rescue nil end |
#extract_headers_for_background(request) ⇒ Object
Extract serializable headers needed for background processing Override in gateways that need additional headers
84 85 86 87 88 89 |
# File 'lib/flow_chat/gateway_async_support.rb', line 84 def extract_headers_for_background(request) { "Content-Type" => request.headers["Content-Type"], "User-Agent" => request.headers["User-Agent"] }.compact end |
#extract_host(request) ⇒ Object
Extract host from request for URL boundary support
92 93 94 95 96 |
# File 'lib/flow_chat/gateway_async_support.rb', line 92 def extract_host(request) request.host rescue nil end |
#extract_path(request) ⇒ Object
Extract path from request for URL boundary support
99 100 101 102 103 |
# File 'lib/flow_chat/gateway_async_support.rb', line 99 def extract_path(request) request.path rescue nil end |
#extract_remote_ip(request) ⇒ Object
Extract remote IP from request
118 119 120 121 122 |
# File 'lib/flow_chat/gateway_async_support.rb', line 118 def extract_remote_ip(request) request.remote_ip rescue nil end |
#in_background? ⇒ Boolean
Detect if we're currently in background mode
16 17 18 |
# File 'lib/flow_chat/gateway_async_support.rb', line 16 def in_background? @controller.is_a?(::FlowChat::BackgroundController) end |
#should_enqueue_async? ⇒ Boolean
Check if async processing should be used Returns true if:
- Not already in background mode
- Processor has async enabled
- Gateway supports async
37 38 39 40 41 42 43 |
# File 'lib/flow_chat/gateway_async_support.rb', line 37 def should_enqueue_async? processor = @context["processor"] !in_background? && processor&.async_enabled? && async_supported? end |
#side_events_already_published? ⇒ Boolean
Whether an earlier pass already announced this delivery's side events, which is the case only for a job the gem enqueued after publishing them itself. Being in the background is not enough on its own: an application may build a request context and enqueue a job with no foreground pass ahead of it, and then this pass is the first to see the delivery.
in_background? short-circuits because a foreground controller is a Rails controller, which knows nothing about side events.
28 29 30 |
# File 'lib/flow_chat/gateway_async_support.rb', line 28 def side_events_already_published? in_background? && @controller.side_events_published? end |