graphql-anycable 1.0.1 → 1.1.0

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: 2ff33e113bf80dad3da7cab49606e37f7b3b69783ce4e8b2bb0466bf3e636881
4
- data.tar.gz: 6c9c58824c29cf9d35e7dc82c70c32b8e398c5482847f888133de5e9fb5ebdb9
3
+ metadata.gz: 335a3ba62f65f0d6dfdd5eab2e1361382d192b5fbc910c591ced6f78296fb4ff
4
+ data.tar.gz: 9f392057c605fc0b74d6ea2c940409540b87e25ddb0a6dee34e47ad3929f652a
5
5
  SHA512:
6
- metadata.gz: 11f689864709223c38a4441b2546f285389ff7d32b694cc983ebda2cc3e829b271686eb25e2d2ca3df3bafa36d2b12ec61b6cb043c28b1b11b98683efb21c2d8
7
- data.tar.gz: d973bb2885f9991b3be3fb13f0c8fec2c7815b67b993ced900d53812d0b661433f3db99cf193ee2b827c57ab59ea1d7111c34d6c8a8cf1923f8b01dfedebc34a
6
+ metadata.gz: 55b8fbf37efbdeff43beb7266ed627491b1a592f9cfe7e803dfd420b49d988a8057cb4ad7df7dea916df4f4c555868e29bace42cc76d2ae692755421a05f8bd5
7
+ data.tar.gz: d0665b9ec01879f5898c7638a9325c156c2665966552edc20cd013d3dfefbbbbada8e7e22d32e31ce7d8e6e0f59576c9a377ff92ffd1eb8e674e4cef533c7659
@@ -18,19 +18,19 @@ jobs:
18
18
  include:
19
19
  - ruby: "3.0"
20
20
  graphql: '~> 1.12.0'
21
- anycable: '~> 1.0.0'
21
+ anycable: '~> 1.1.0'
22
22
  interpreter: yes
23
23
  - ruby: "3.0"
24
24
  graphql: '~> 1.12.0'
25
- anycable: '~> 1.0.0'
25
+ anycable: '~> 1.1.0'
26
26
  interpreter: no
27
27
  - ruby: 2.7
28
28
  graphql: '~> 1.12.0'
29
- anycable: '~> 1.0.0'
29
+ anycable: '~> 1.1.0'
30
30
  interpreter: yes
31
31
  - ruby: 2.7
32
32
  graphql: '~> 1.12.0'
33
- anycable: '~> 1.0.0'
33
+ anycable: '~> 1.1.0'
34
34
  interpreter: no
35
35
  - ruby: 2.6
36
36
  graphql: '~> 1.11.0'
data/CHANGELOG.md CHANGED
@@ -7,6 +7,26 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
7
7
 
8
8
  ## Unreleased
9
9
 
10
+ ## 1.1.0 - 2021-11-17
11
+
12
+ ### Added
13
+
14
+ - Support for generating unique channel IDs server-side and storing them in the channel states.
15
+
16
+ Currently, we rely on `params["channelId"]` to track subscriptions. This value is random when using `graphql-ruby` JS client, but is not guaranteed to be random in general.
17
+
18
+ Now you can opt-in to use server-side IDs by specifying `use_client_provided_uniq_id: false` in YAML config or thru the `GRAPHQL_ANYCABLE_USE_CLIENT_PROVIDED_UNIQ_ID=false` env var.
19
+
20
+ NOTE: Relying on client-side IDs is deprecated and will be removed in the future versions.
21
+
22
+ You must also update your cleanup code in the `Channel#unsubscribed`:
23
+
24
+ ```diff
25
+ - channel_id = params.fetch("channelId")
26
+ - MySchema.subscriptions.delete_channel_subscriptions(channel_id)
27
+ + MySchema.subscriptions.delete_channel_subscriptions(self)
28
+ ```
29
+
10
30
  ## 1.0.1 - 2021-04-16
11
31
 
12
32
  ### Added
data/README.md CHANGED
@@ -77,8 +77,7 @@ Or install it yourself as:
77
77
  end
78
78
 
79
79
  def unsubscribed
80
- channel_id = params.fetch("channelId")
81
- MySchema.subscriptions.delete_channel_subscriptions(channel_id)
80
+ MySchema.subscriptions.delete_channel_subscriptions(self)
82
81
  end
83
82
 
84
83
  private
@@ -142,6 +141,7 @@ GraphQL-AnyCable uses [anyway_config] to configure itself. There are several pos
142
141
  GRAPHQL_ANYCABLE_SUBSCRIPTION_EXPIRATION_SECONDS=604800
143
142
  GRAPHQL_ANYCABLE_USE_REDIS_OBJECT_ON_CLEANUP=true
144
143
  GRAPHQL_ANYCABLE_HANDLE_LEGACY_SUBSCRIPTIONS=false
144
+ GRAPHQL_ANYCABLE_USE_CLIENT_PROVIDED_UNIQ_ID=false
145
145
  ```
146
146
 
147
147
  2. YAML configuration files:
@@ -152,6 +152,7 @@ GraphQL-AnyCable uses [anyway_config] to configure itself. There are several pos
152
152
  subscription_expiration_seconds: 300 # 5 minutes
153
153
  use_redis_object_on_cleanup: false # For restricted redis installations
154
154
  handle_legacy_subscriptions: false # For seamless upgrade from pre-1.0 versions
155
+ use_client_provided_uniq_id: false # To avoid problems with non-uniqueness of Apollo channel identifiers
155
156
  ```
156
157
 
157
158
  3. Configuration from your application code:
@@ -11,6 +11,15 @@ module GraphQL
11
11
  attr_config subscription_expiration_seconds: nil
12
12
  attr_config use_redis_object_on_cleanup: true
13
13
  attr_config handle_legacy_subscriptions: false
14
+ attr_config use_client_provided_uniq_id: true
15
+
16
+ on_load do
17
+ next unless use_client_provided_uniq_id?
18
+
19
+ warn "[Deprecated] Using client provided channel uniq IDs could lead to unexpected behaviour, " \
20
+ " please, set GraphQL::AnyCable.config.use_client_provided_uniq_id = false or GRAPHQL_ANYCABLE_USE_CLIENT_PROVIDED_UNIQ_ID=false, " \
21
+ " and update the `#unsubscribed` callback code according to the latest docs."
22
+ end
14
23
  end
15
24
  end
16
25
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module GraphQL
4
4
  module AnyCable
5
- VERSION = "1.0.1"
5
+ VERSION = "1.1.0"
6
6
  end
7
7
  end
@@ -45,8 +45,7 @@ require "graphql/anycable/errors"
45
45
  # end
46
46
  #
47
47
  # def unsubscribed
48
- # channel_id = params.fetch("channelId")
49
- # MySchema.subscriptions.delete_channel_subscriptions(channel_id)
48
+ # MySchema.subscriptions.delete_channel_subscriptions(self)
50
49
  # end
51
50
  # end
52
51
  #
@@ -143,6 +142,12 @@ module GraphQL
143
142
 
144
143
  raise GraphQL::AnyCable::ChannelConfigurationError unless channel
145
144
 
145
+ channel_uniq_id = config.use_client_provided_uniq_id? ? channel.params["channelId"] : subscription_id
146
+
147
+ # Store subscription_id in the channel state to cleanup on disconnect
148
+ write_subscription_id(channel, channel_uniq_id)
149
+
150
+
146
151
  events.each do |event|
147
152
  channel.stream_from(SUBSCRIPTIONS_PREFIX + event.fingerprint)
148
153
  end
@@ -156,14 +161,14 @@ module GraphQL
156
161
  }
157
162
 
158
163
  redis.multi do
159
- redis.sadd(CHANNEL_PREFIX + channel.params["channelId"], subscription_id)
164
+ redis.sadd(CHANNEL_PREFIX + channel_uniq_id, subscription_id)
160
165
  redis.mapped_hmset(SUBSCRIPTION_PREFIX + subscription_id, data)
161
166
  events.each do |event|
162
167
  redis.zincrby(FINGERPRINTS_PREFIX + event.topic, 1, event.fingerprint)
163
168
  redis.sadd(SUBSCRIPTIONS_PREFIX + event.fingerprint, subscription_id)
164
169
  end
165
170
  next unless config.subscription_expiration_seconds
166
- redis.expire(CHANNEL_PREFIX + channel.params["channelId"], config.subscription_expiration_seconds)
171
+ redis.expire(CHANNEL_PREFIX + channel_uniq_id, config.subscription_expiration_seconds)
167
172
  redis.expire(SUBSCRIPTION_PREFIX + subscription_id, config.subscription_expiration_seconds)
168
173
  end
169
174
  end
@@ -217,7 +222,9 @@ module GraphQL
217
222
  end
218
223
 
219
224
  # The channel was closed, forget about it and its subscriptions
220
- def delete_channel_subscriptions(channel_id)
225
+ def delete_channel_subscriptions(channel_or_id)
226
+ # For backward compatibility
227
+ channel_id = channel_or_id.is_a?(String) ? channel_or_id : read_subscription_id(channel_or_id)
221
228
  redis.smembers(CHANNEL_PREFIX + channel_id).each do |subscription_id|
222
229
  delete_subscription(subscription_id)
223
230
  end
@@ -229,6 +236,17 @@ module GraphQL
229
236
  def anycable
230
237
  @anycable ||= ::AnyCable.broadcast_adapter
231
238
  end
239
+
240
+ def read_subscription_id(channel)
241
+ return channel.instance_variable_get(:@__sid__) if channel.instance_variable_defined?(:@__sid__)
242
+
243
+ channel.instance_variable_set(:@__sid__, channel.connection.socket.istate["sid"])
244
+ end
245
+
246
+ def write_subscription_id(channel, val)
247
+ channel.connection.socket.istate["sid"] = val
248
+ channel.instance_variable_set(:@__sid__, val)
249
+ end
232
250
  end
233
251
  end
234
252
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql-anycable
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrey Novikov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-04-16 00:00:00.000000000 Z
11
+ date: 2021-11-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: anycable