solid_cable 3.0.4 → 3.0.6

Sign up to get free protection for your applications and to get access to all the features.
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