solid_cable 3.0.4 → 3.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8c170646d1e8ca3c96edceaf9675ee554eb181229d3e61abff68746e07ecd061
4
- data.tar.gz: ec9c141f177cb5e4c52b5ff8e2b0c915e048a892a47a8d50a854fe708a9a556e
3
+ metadata.gz: 807dfe75fdc4577c47485b8af3a296eddc6655f53d2294bc831fc1862127214e
4
+ data.tar.gz: 48b1b21d6e60e0532f6a7ea542e3cda8384d4178256c81cffa184c4bebaee721
5
5
  SHA512:
6
- metadata.gz: 225dcdba255693a45f6c1e8fd33982b27a4a75fc70ba6da64275aecf3140c819d5a0ef49d88c37de92318483783dac0a9a19e77c7be79efdc8403d42a8413162
7
- data.tar.gz: 32bec49c5542d5dff12a14b2ed041644dc6e73894618f85d45eaad6ae8dab1fa1177a9029abc37ec04a1c24285b4d39d7ebd6e1c58f60cdff03fa75fa7ab24d6
6
+ metadata.gz: '099db3f19f50a76ea75881f3a01efc73a0ae1a60aee20cce9f8be0e06dc9cfe3de5beb574a212cc34d2eca33103e367d4d09a649340b49777c76bda09bb04320'
7
+ data.tar.gz: e519ed0fcd86350fd107db0d90717466676029f9471f26b9544bd970684d39993b0585b8d4c848b482bca21aa2924de4f8790655f7a36c4cb0d7bc10c5f91610
@@ -3,6 +3,7 @@
3
3
  require "action_cable/subscription_adapter/base"
4
4
  require "action_cable/subscription_adapter/channel_prefix"
5
5
  require "action_cable/subscription_adapter/subscriber_map"
6
+ require "concurrent/atomic/semaphore"
6
7
 
7
8
  module ActionCable
8
9
  module SubscriptionAdapter
@@ -38,28 +39,53 @@ module ActionCable
38
39
  end
39
40
 
40
41
  class Listener < ::ActionCable::SubscriptionAdapter::SubscriberMap
42
+ Stop = Class.new(Exception)
43
+
41
44
  def initialize(event_loop)
42
45
  super()
43
46
 
44
47
  @event_loop = event_loop
45
48
 
49
+ # Critical section begins with 0 permits. It can be understood as
50
+ # being "normally held" by the listener thread. It is released
51
+ # for specific sections of code, rather than acquired.
52
+ @critical = Concurrent::Semaphore.new(0)
53
+
46
54
  @thread = Thread.new do
47
- Thread.current.abort_on_exception = true
48
55
  listen
49
56
  end
50
57
  end
51
58
 
52
59
  def listen
53
- while running?
54
- with_polling_volume { broadcast_messages }
60
+ loop do
61
+ begin
62
+ instance = interruptible { Rails.application.executor.run! }
63
+ with_polling_volume { broadcast_messages }
64
+ ensure
65
+ instance.complete! if instance
66
+ end
55
67
 
56
- sleep ::SolidCable.polling_interval
68
+ interruptible { sleep ::SolidCable.polling_interval }
57
69
  end
70
+ rescue Stop
71
+ ensure
72
+ @critical.release
73
+ end
74
+
75
+ def interruptible
76
+ @critical.release
77
+ yield
78
+ ensure
79
+ @critical.acquire
58
80
  end
59
81
 
60
82
  def shutdown
61
- self.running = false
62
- Thread.pass while thread.alive?
83
+ @critical.acquire
84
+ # We have the critical permit, and so the listen thread must be
85
+ # safe to interrupt.
86
+ thread.raise(Stop)
87
+ @critical.release
88
+ thread.join
63
89
  end
64
90
 
65
91
  def add_channel(channel, on_success)
@@ -77,15 +103,7 @@ module ActionCable
77
103
 
78
104
  private
79
105
  attr_reader :event_loop, :thread
80
- attr_writer :running, :last_id
81
-
82
- def running?
83
- if defined?(@running)
84
- @running
85
- else
86
- self.running = true
87
- end
88
- end
106
+ attr_writer :last_id
89
107
 
90
108
  def last_id
91
109
  @last_id ||= ::SolidCable::Message.maximum(:id) || 0
@@ -96,12 +114,10 @@ module ActionCable
96
114
  end
97
115
 
98
116
  def broadcast_messages
99
- Rails.application.executor.wrap do
100
- ::SolidCable::Message.broadcastable(channels, last_id).
101
- each do |message|
102
- broadcast(message.channel, message.payload)
103
- self.last_id = message.id
104
- end
117
+ ::SolidCable::Message.broadcastable(channels, last_id).
118
+ each do |message|
119
+ broadcast(message.channel, message.payload)
120
+ self.last_id = message.id
105
121
  end
106
122
  end
107
123
 
@@ -112,6 +128,37 @@ module ActionCable
112
128
  yield
113
129
  end
114
130
  end
131
+
132
+ def wake_up
133
+ interrupt
134
+ end
135
+
136
+ SELF_PIPE_BLOCK_SIZE = 11
137
+
138
+ def interrupt
139
+ self_pipe[:writer].write_nonblock(".")
140
+ rescue Errno::EAGAIN, Errno::EINTR
141
+ # Ignore writes that would block and retry
142
+ # if another signal arrived while writing
143
+ retry
144
+ end
145
+
146
+ def interruptible_sleep(time)
147
+ if time > 0 && self_pipe[:reader].wait_readable(time)
148
+ loop { self_pipe[:reader].read_nonblock(SELF_PIPE_BLOCK_SIZE) }
149
+ end
150
+ rescue Errno::EAGAIN, Errno::EINTR
151
+ end
152
+
153
+ # Self-pipe for signal-handling (http://cr.yp.to/docs/selfpipe.html)
154
+ def self_pipe
155
+ @self_pipe ||= create_self_pipe
156
+ end
157
+
158
+ def create_self_pipe
159
+ reader, writer = IO.pipe
160
+ { reader: reader, writer: writer }
161
+ end
115
162
  end
116
163
  end
117
164
  end
@@ -5,6 +5,6 @@ class SolidCable::InstallGenerator < Rails::Generators::Base
5
5
 
6
6
  def copy_files
7
7
  template "db/cable_schema.rb"
8
- template "config/cable.yml", force: true
8
+ template "config/cable.yml"
9
9
  end
10
10
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolidCable
4
- VERSION = "3.0.4"
4
+ VERSION = "3.0.6"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solid_cable
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.4
4
+ version: 3.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Pezza
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-12-06 00:00:00.000000000 Z
11
+ date: 2025-01-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord