chat_sdk-state-mysql 1.1.0 → 1.3.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 +4 -4
- data/lib/chat_sdk/state/mysql.rb +69 -19
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 83d39209e4718ceeac4fe28d88e7bb00b26649fc64169828e05d17ace894f2d3
|
|
4
|
+
data.tar.gz: 16bfde09613137f441d82a8e7720eb2515307569f875b7d542120e4144c2787b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1f133d05b7ccee5344360ee84ff68efff1a44b89e3e31084d780d90451ab64de8e51a13559166394173715cfece2a41870fe4387479253c055083f586e08814f
|
|
7
|
+
data.tar.gz: 97699fbd0e4063ed56b1eff2c12e05d1825cf089ef8dcd23414345b414d9eb849c43391e6ed268915b3bb201e71ce2b937b8665950a1b5473bd19213032bdde4
|
data/lib/chat_sdk/state/mysql.rb
CHANGED
|
@@ -3,10 +3,37 @@
|
|
|
3
3
|
require "chat_sdk"
|
|
4
4
|
require "mysql2"
|
|
5
5
|
require "json"
|
|
6
|
+
require "uri"
|
|
6
7
|
|
|
7
8
|
module ChatSDK
|
|
8
9
|
module State
|
|
9
10
|
class Mysql < Base
|
|
11
|
+
def self.parse_url(url)
|
|
12
|
+
uri = URI.parse(url)
|
|
13
|
+
options = {}
|
|
14
|
+
options[:host] = uri.host if uri.host
|
|
15
|
+
options[:port] = uri.port if uri.port
|
|
16
|
+
options[:username] = URI::DEFAULT_PARSER.unescape(uri.user) if uri.user
|
|
17
|
+
options[:password] = URI::DEFAULT_PARSER.unescape(uri.password) if uri.password
|
|
18
|
+
database = uri.path.delete_prefix("/")
|
|
19
|
+
options[:database] = URI::DEFAULT_PARSER.unescape(database) unless database.empty?
|
|
20
|
+
query_options = URI.decode_www_form(uri.query.to_s).to_h
|
|
21
|
+
query_options.transform_values! do |value|
|
|
22
|
+
case value
|
|
23
|
+
when /\A\d+\z/
|
|
24
|
+
value.to_i
|
|
25
|
+
when "true"
|
|
26
|
+
true
|
|
27
|
+
when "false"
|
|
28
|
+
false
|
|
29
|
+
else
|
|
30
|
+
value
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
options.merge!(query_options.transform_keys(&:to_sym))
|
|
34
|
+
options
|
|
35
|
+
end
|
|
36
|
+
|
|
10
37
|
def initialize(url: nil, connection: nil, key_prefix: "chat_sdk", auto_migrate: true)
|
|
11
38
|
@conn = connection || connect(url || ENV["MYSQL_URL"] || ENV["DATABASE_URL"] || "mysql2://root@localhost/chat_sdk_dev")
|
|
12
39
|
@key_prefix = key_prefix
|
|
@@ -44,15 +71,15 @@ module ChatSDK
|
|
|
44
71
|
def acquire_lock(key, owner:, ttl:)
|
|
45
72
|
ttl_seconds = ttl.to_f
|
|
46
73
|
del_stmt = @conn.prepare(
|
|
47
|
-
"DELETE FROM chat_sdk_locks WHERE key_prefix = ? AND lock_key = ? AND expires_at < NOW()"
|
|
74
|
+
"DELETE FROM chat_sdk_locks WHERE key_prefix = ? AND lock_key = ? AND expires_at < NOW(6)"
|
|
48
75
|
)
|
|
49
76
|
del_stmt.execute(@key_prefix, key)
|
|
50
77
|
ins_stmt = @conn.prepare(
|
|
51
78
|
"INSERT IGNORE INTO chat_sdk_locks (key_prefix, lock_key, owner, expires_at) " \
|
|
52
|
-
"VALUES (?, ?, ?, DATE_ADD(NOW(), INTERVAL #{ttl_seconds} SECOND))"
|
|
79
|
+
"VALUES (?, ?, ?, DATE_ADD(NOW(6), INTERVAL #{ttl_seconds} SECOND))"
|
|
53
80
|
)
|
|
54
81
|
ins_stmt.execute(@key_prefix, key, owner)
|
|
55
|
-
|
|
82
|
+
ins_stmt.affected_rows > 0
|
|
56
83
|
end
|
|
57
84
|
|
|
58
85
|
def release_lock(key, owner:)
|
|
@@ -60,14 +87,14 @@ module ChatSDK
|
|
|
60
87
|
"DELETE FROM chat_sdk_locks WHERE key_prefix = ? AND lock_key = ? AND owner = ?"
|
|
61
88
|
)
|
|
62
89
|
stmt.execute(@key_prefix, key, owner)
|
|
63
|
-
|
|
90
|
+
stmt.affected_rows > 0
|
|
64
91
|
end
|
|
65
92
|
|
|
66
93
|
def force_lock(key, owner:, ttl:)
|
|
67
94
|
ttl_seconds = ttl.to_f
|
|
68
95
|
stmt = @conn.prepare(
|
|
69
96
|
"INSERT INTO chat_sdk_locks (key_prefix, lock_key, owner, expires_at) " \
|
|
70
|
-
"VALUES (?, ?, ?, DATE_ADD(NOW(), INTERVAL #{ttl_seconds} SECOND)) " \
|
|
97
|
+
"VALUES (?, ?, ?, DATE_ADD(NOW(6), INTERVAL #{ttl_seconds} SECOND)) " \
|
|
71
98
|
"ON DUPLICATE KEY UPDATE owner = VALUES(owner), expires_at = VALUES(expires_at)"
|
|
72
99
|
)
|
|
73
100
|
stmt.execute(@key_prefix, key, owner)
|
|
@@ -76,18 +103,18 @@ module ChatSDK
|
|
|
76
103
|
|
|
77
104
|
def extend_lock(key, owner:, ttl:)
|
|
78
105
|
stmt = @conn.prepare(
|
|
79
|
-
"UPDATE chat_sdk_locks SET expires_at = DATE_ADD(NOW(), INTERVAL #{ttl.to_f} SECOND) " \
|
|
80
|
-
"WHERE key_prefix = ? AND lock_key = ? AND owner = ? AND expires_at > NOW()"
|
|
106
|
+
"UPDATE chat_sdk_locks SET expires_at = DATE_ADD(NOW(6), INTERVAL #{ttl.to_f} SECOND) " \
|
|
107
|
+
"WHERE key_prefix = ? AND lock_key = ? AND owner = ? AND expires_at > NOW(6)"
|
|
81
108
|
)
|
|
82
109
|
stmt.execute(@key_prefix, key, owner)
|
|
83
|
-
|
|
110
|
+
stmt.affected_rows > 0
|
|
84
111
|
end
|
|
85
112
|
|
|
86
113
|
# Key-value store
|
|
87
114
|
|
|
88
115
|
def get(key)
|
|
89
116
|
stmt = @conn.prepare(
|
|
90
|
-
"SELECT value FROM chat_sdk_cache WHERE key_prefix = ? AND cache_key = ? AND (expires_at IS NULL OR expires_at > NOW())"
|
|
117
|
+
"SELECT value FROM chat_sdk_cache WHERE key_prefix = ? AND cache_key = ? AND (expires_at IS NULL OR expires_at > NOW(6))"
|
|
91
118
|
)
|
|
92
119
|
result = stmt.execute(@key_prefix, key)
|
|
93
120
|
row = result.first
|
|
@@ -101,7 +128,7 @@ module ChatSDK
|
|
|
101
128
|
stmt = if ttl
|
|
102
129
|
@conn.prepare(
|
|
103
130
|
"INSERT INTO chat_sdk_cache (key_prefix, cache_key, value, expires_at) " \
|
|
104
|
-
"VALUES (?, ?, ?, DATE_ADD(NOW(), INTERVAL #{ttl.to_f} SECOND)) " \
|
|
131
|
+
"VALUES (?, ?, ?, DATE_ADD(NOW(6), INTERVAL #{ttl.to_f} SECOND)) " \
|
|
105
132
|
"ON DUPLICATE KEY UPDATE value = VALUES(value), expires_at = VALUES(expires_at)"
|
|
106
133
|
)
|
|
107
134
|
else
|
|
@@ -129,13 +156,13 @@ module ChatSDK
|
|
|
129
156
|
def set_if_absent(key, value, ttl: nil)
|
|
130
157
|
serialized = JSON.generate(value)
|
|
131
158
|
del_stmt = @conn.prepare(
|
|
132
|
-
"DELETE FROM chat_sdk_cache WHERE key_prefix = ? AND cache_key = ? AND expires_at IS NOT NULL AND expires_at < NOW()"
|
|
159
|
+
"DELETE FROM chat_sdk_cache WHERE key_prefix = ? AND cache_key = ? AND expires_at IS NOT NULL AND expires_at < NOW(6)"
|
|
133
160
|
)
|
|
134
161
|
del_stmt.execute(@key_prefix, key)
|
|
135
162
|
stmt = if ttl
|
|
136
163
|
@conn.prepare(
|
|
137
164
|
"INSERT IGNORE INTO chat_sdk_cache (key_prefix, cache_key, value, expires_at) " \
|
|
138
|
-
"VALUES (?, ?, ?, DATE_ADD(NOW(), INTERVAL #{ttl.to_f} SECOND))"
|
|
165
|
+
"VALUES (?, ?, ?, DATE_ADD(NOW(6), INTERVAL #{ttl.to_f} SECOND))"
|
|
139
166
|
)
|
|
140
167
|
else
|
|
141
168
|
@conn.prepare(
|
|
@@ -144,7 +171,7 @@ module ChatSDK
|
|
|
144
171
|
)
|
|
145
172
|
end
|
|
146
173
|
stmt.execute(@key_prefix, key, serialized)
|
|
147
|
-
|
|
174
|
+
stmt.affected_rows > 0
|
|
148
175
|
end
|
|
149
176
|
|
|
150
177
|
def enqueue(key, value, max_size:, drop: :drop_oldest)
|
|
@@ -208,11 +235,11 @@ module ChatSDK
|
|
|
208
235
|
|
|
209
236
|
def cleanup_expired
|
|
210
237
|
s1 = @conn.prepare(
|
|
211
|
-
"DELETE FROM chat_sdk_cache WHERE key_prefix = ? AND expires_at IS NOT NULL AND expires_at < NOW()"
|
|
238
|
+
"DELETE FROM chat_sdk_cache WHERE key_prefix = ? AND expires_at IS NOT NULL AND expires_at < NOW(6)"
|
|
212
239
|
)
|
|
213
240
|
s1.execute(@key_prefix)
|
|
214
241
|
s2 = @conn.prepare(
|
|
215
|
-
"DELETE FROM chat_sdk_locks WHERE key_prefix = ? AND expires_at < NOW()"
|
|
242
|
+
"DELETE FROM chat_sdk_locks WHERE key_prefix = ? AND expires_at < NOW(6)"
|
|
216
243
|
)
|
|
217
244
|
s2.execute(@key_prefix)
|
|
218
245
|
end
|
|
@@ -220,7 +247,7 @@ module ChatSDK
|
|
|
220
247
|
private
|
|
221
248
|
|
|
222
249
|
def connect(url)
|
|
223
|
-
Mysql2::Client.new(url)
|
|
250
|
+
Mysql2::Client.new(self.class.parse_url(url))
|
|
224
251
|
end
|
|
225
252
|
|
|
226
253
|
def ensure_tables
|
|
@@ -237,7 +264,7 @@ module ChatSDK
|
|
|
237
264
|
key_prefix VARCHAR(255) NOT NULL,
|
|
238
265
|
lock_key VARCHAR(512) NOT NULL,
|
|
239
266
|
owner VARCHAR(255) NOT NULL,
|
|
240
|
-
expires_at TIMESTAMP NOT NULL,
|
|
267
|
+
expires_at TIMESTAMP(6) NOT NULL,
|
|
241
268
|
PRIMARY KEY (key_prefix, lock_key)
|
|
242
269
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
|
|
243
270
|
SQL
|
|
@@ -246,7 +273,7 @@ module ChatSDK
|
|
|
246
273
|
key_prefix VARCHAR(255) NOT NULL,
|
|
247
274
|
cache_key VARCHAR(512) NOT NULL,
|
|
248
275
|
value JSON NOT NULL,
|
|
249
|
-
expires_at TIMESTAMP NULL DEFAULT NULL,
|
|
276
|
+
expires_at TIMESTAMP(6) NULL DEFAULT NULL,
|
|
250
277
|
PRIMARY KEY (key_prefix, cache_key)
|
|
251
278
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
|
|
252
279
|
SQL
|
|
@@ -258,9 +285,32 @@ module ChatSDK
|
|
|
258
285
|
value JSON NOT NULL,
|
|
259
286
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
260
287
|
PRIMARY KEY (id),
|
|
261
|
-
INDEX chat_sdk_queues_lookup (key_prefix, queue_key
|
|
288
|
+
INDEX chat_sdk_queues_lookup (key_prefix, queue_key)
|
|
262
289
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
|
|
263
290
|
SQL
|
|
291
|
+
ensure_expiration_precision
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
def ensure_expiration_precision
|
|
295
|
+
columns = @conn.query(<<~SQL).each_with_object({}) do |row, result|
|
|
296
|
+
SELECT TABLE_NAME, DATETIME_PRECISION
|
|
297
|
+
FROM information_schema.columns
|
|
298
|
+
WHERE table_schema = DATABASE()
|
|
299
|
+
AND table_name IN ('chat_sdk_locks', 'chat_sdk_cache')
|
|
300
|
+
AND column_name = 'expires_at'
|
|
301
|
+
SQL
|
|
302
|
+
result[row["TABLE_NAME"]] = row["DATETIME_PRECISION"].to_i
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
definitions = {
|
|
306
|
+
"chat_sdk_locks" => "TIMESTAMP(6) NOT NULL",
|
|
307
|
+
"chat_sdk_cache" => "TIMESTAMP(6) NULL DEFAULT NULL"
|
|
308
|
+
}
|
|
309
|
+
definitions.each do |table_name, definition|
|
|
310
|
+
next if columns[table_name] == 6
|
|
311
|
+
|
|
312
|
+
@conn.query("ALTER TABLE #{table_name} MODIFY expires_at #{definition}")
|
|
313
|
+
end
|
|
264
314
|
end
|
|
265
315
|
end
|
|
266
316
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: chat_sdk-state-mysql
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Quentin Rousseau
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: '
|
|
18
|
+
version: '1.2'
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: '
|
|
25
|
+
version: '1.2'
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: mysql2
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|