undertow 0.1.0 → 0.2.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/undertow/buffer.rb +21 -39
- data/lib/undertow/configuration.rb +19 -9
- data/lib/undertow/drain_job.rb +5 -5
- data/lib/undertow/dsl.rb +5 -5
- data/lib/undertow/store/base.rb +48 -0
- data/lib/undertow/store/memory_store.rb +62 -0
- data/lib/undertow/store/redis_store.rb +61 -0
- data/lib/undertow/trackable.rb +6 -6
- data/lib/undertow/version.rb +1 -1
- data/lib/undertow.rb +5 -2
- data/undertow.gemspec +1 -2
- metadata +5 -16
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0b2c91ae2e1c3eafff3e52438ca4a8c2e2856fd83c2c1097708d3e7f2ed457be
|
|
4
|
+
data.tar.gz: 385394ce28a3034f17d4e89d3d00528931f38c44a180b338c5bfb43c83b4877b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 57614c035d133873d7f3c9b881bc6c59de51c0f2add8bc860eb059f955bdd4cc7a57576e99df1085576db5b64fbdfd7c6b4376136093b46ed259e2e70dc3f87b
|
|
7
|
+
data.tar.gz: 20cca40fdfe6459d18b264050ce5db678d6d94e537d3bd19a7fbe3a61fb5b7e32bb13bd859a88d263f20d8df4473cc178d6796470d609add092d66ca60229da9
|
data/lib/undertow/buffer.rb
CHANGED
|
@@ -1,98 +1,80 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Undertow
|
|
4
|
-
# Low-level
|
|
5
|
-
# All methods are no-ops when
|
|
4
|
+
# Low-level set operations used by Trackable callbacks and DrainJob.
|
|
5
|
+
# Delegates to the configured store adapter. All methods are no-ops when
|
|
6
|
+
# tracking is disabled.
|
|
6
7
|
module Buffer
|
|
7
8
|
class << self
|
|
8
9
|
def push_pending(model_name, ids)
|
|
9
10
|
return if Undertow.tracking_disabled?
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
r.sadd(Registry::MODELS_KEY, model_name)
|
|
14
|
-
end
|
|
12
|
+
store.add_members(Registry.pending_key(model_name), ids)
|
|
13
|
+
store.add_members(Registry::MODELS_KEY, model_name)
|
|
15
14
|
end
|
|
16
15
|
|
|
17
16
|
def push_deleted(model_name, ids)
|
|
18
17
|
return if Undertow.tracking_disabled?
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
r.sadd(Registry::MODELS_KEY, model_name)
|
|
23
|
-
end
|
|
19
|
+
store.add_members(Registry.deleted_key(model_name), ids)
|
|
20
|
+
store.add_members(Registry::MODELS_KEY, model_name)
|
|
24
21
|
end
|
|
25
22
|
|
|
26
23
|
def pop_pending(model_name, count)
|
|
27
|
-
|
|
24
|
+
store.pop_members(Registry.pending_key(model_name), count)
|
|
28
25
|
end
|
|
29
26
|
|
|
30
27
|
def pop_deleted(model_name, count)
|
|
31
|
-
|
|
28
|
+
store.pop_members(Registry.deleted_key(model_name), count)
|
|
32
29
|
end
|
|
33
30
|
|
|
34
31
|
def pending_model_names
|
|
35
|
-
|
|
32
|
+
store.members(Registry::MODELS_KEY)
|
|
36
33
|
end
|
|
37
34
|
|
|
38
35
|
def deregister_model(model_name)
|
|
39
|
-
|
|
36
|
+
store.remove_member(Registry::MODELS_KEY, model_name)
|
|
40
37
|
end
|
|
41
38
|
|
|
42
39
|
def reregister_model(model_name)
|
|
43
|
-
|
|
40
|
+
store.add_members(Registry::MODELS_KEY, model_name)
|
|
44
41
|
end
|
|
45
42
|
|
|
46
43
|
def remaining(model_name)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
r.scard(Registry.deleted_key(model_name))
|
|
50
|
-
end || 0
|
|
44
|
+
store.member_count(Registry.pending_key(model_name)) +
|
|
45
|
+
store.member_count(Registry.deleted_key(model_name))
|
|
51
46
|
end
|
|
52
47
|
|
|
53
48
|
def restore_pending(model_name, ids)
|
|
54
|
-
|
|
49
|
+
store.add_members(Registry.pending_key(model_name), ids) if ids.any?
|
|
55
50
|
end
|
|
56
51
|
|
|
57
52
|
def restore_deleted(model_name, ids)
|
|
58
|
-
|
|
53
|
+
store.add_members(Registry.deleted_key(model_name), ids) if ids.any?
|
|
59
54
|
end
|
|
60
55
|
|
|
61
56
|
def pending?
|
|
62
|
-
|
|
57
|
+
store.member_count(Registry::MODELS_KEY).positive?
|
|
63
58
|
end
|
|
64
59
|
|
|
65
|
-
# Acquire the distributed drain lock using SET NX. Returns true if the lock
|
|
66
|
-
# was acquired, false if it was already held. TTL is a safety valve in case
|
|
67
|
-
# the job process dies before releasing it.
|
|
68
60
|
def acquire_drain_lock(ttl: 30)
|
|
69
61
|
lock_key = Undertow.configuration.drain_lock_key
|
|
70
62
|
return true unless lock_key
|
|
71
63
|
|
|
72
|
-
|
|
64
|
+
store.lock_acquire(lock_key, ttl: ttl)
|
|
73
65
|
end
|
|
74
66
|
|
|
75
|
-
# Release the drain lock. Called at the start of DrainJob#perform so the
|
|
76
|
-
# scheduler can enqueue another job for IDs that arrive while this one runs.
|
|
77
67
|
def release_drain_lock
|
|
78
68
|
lock_key = Undertow.configuration.drain_lock_key
|
|
79
69
|
return unless lock_key
|
|
80
70
|
|
|
81
|
-
|
|
71
|
+
store.lock_release(lock_key)
|
|
82
72
|
end
|
|
83
73
|
|
|
84
74
|
private
|
|
85
75
|
|
|
86
|
-
def
|
|
87
|
-
|
|
88
|
-
if client.respond_to?(:with)
|
|
89
|
-
client.with { |conn| yield conn }
|
|
90
|
-
else
|
|
91
|
-
yield client
|
|
92
|
-
end
|
|
93
|
-
rescue Redis::BaseConnectionError, Redis::CommandError => e
|
|
94
|
-
Rails.logger.error("Undertow: Redis error: #{e.message}") if defined?(Rails)
|
|
95
|
-
nil
|
|
76
|
+
def store
|
|
77
|
+
Undertow.configuration.store!
|
|
96
78
|
end
|
|
97
79
|
end
|
|
98
80
|
end
|
|
@@ -2,12 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
module Undertow
|
|
4
4
|
class Configuration
|
|
5
|
-
# A
|
|
6
|
-
#
|
|
5
|
+
# A store adapter (an instance of Undertow::Store::Base). Injected by the
|
|
6
|
+
# host application:
|
|
7
7
|
#
|
|
8
|
-
#
|
|
8
|
+
# # Redis
|
|
9
|
+
# Undertow.configure do |c|
|
|
10
|
+
# c.store = Undertow::Store::RedisStore.new(Redis.new(url: ENV['REDIS_URL']))
|
|
11
|
+
# end
|
|
9
12
|
#
|
|
10
|
-
|
|
13
|
+
|
|
14
|
+
# # In-memory (test / single-process dev)
|
|
15
|
+
# Undertow.configure do |c|
|
|
16
|
+
# c.store = Undertow::Store::MemoryStore.new
|
|
17
|
+
# end
|
|
18
|
+
#
|
|
19
|
+
attr_accessor :store
|
|
11
20
|
|
|
12
21
|
# Maximum number of IDs to pop from the buffer per drain per model.
|
|
13
22
|
attr_accessor :max_batch
|
|
@@ -15,20 +24,21 @@ module Undertow
|
|
|
15
24
|
# ActiveJob queue to use for DrainJob.
|
|
16
25
|
attr_accessor :queue_name
|
|
17
26
|
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
27
|
+
# Key used for the distributed drain lock. The scheduler acquires this lock
|
|
28
|
+
# before enqueueing DrainJob; the job releases it immediately on start so
|
|
29
|
+
# new work arriving mid-drain gets its own job on the next tick.
|
|
21
30
|
# Set to nil to disable lock management entirely.
|
|
22
31
|
attr_accessor :drain_lock_key
|
|
23
32
|
|
|
24
33
|
def initialize
|
|
34
|
+
@store = Undertow::Store::MemoryStore.new
|
|
25
35
|
@max_batch = 1_000
|
|
26
36
|
@queue_name = :undertow
|
|
27
37
|
@drain_lock_key = 'undertow:drain:lock'
|
|
28
38
|
end
|
|
29
39
|
|
|
30
|
-
def
|
|
31
|
-
|
|
40
|
+
def store!
|
|
41
|
+
store or raise 'Undertow.configuration.store is not set'
|
|
32
42
|
end
|
|
33
43
|
end
|
|
34
44
|
end
|
data/lib/undertow/drain_job.rb
CHANGED
|
@@ -5,8 +5,8 @@ module Undertow
|
|
|
5
5
|
# each model's configured on_drain handler.
|
|
6
6
|
#
|
|
7
7
|
# Publishes two ActiveSupport::Notifications events:
|
|
8
|
-
# drain.undertow
|
|
9
|
-
# error.undertow
|
|
8
|
+
# drain.undertow , after a successful on_drain call ({ model:, ids:, deleted_ids: })
|
|
9
|
+
# error.undertow , when on_drain raises ({ model:, exception: })
|
|
10
10
|
class DrainJob < ActiveJob::Base
|
|
11
11
|
queue_as { Undertow.configuration.queue_name }
|
|
12
12
|
|
|
@@ -26,7 +26,7 @@ module Undertow
|
|
|
26
26
|
def drain_model(model_name)
|
|
27
27
|
max = Undertow.configuration.max_batch
|
|
28
28
|
|
|
29
|
-
# Deregister before popping
|
|
29
|
+
# Deregister before popping, any concurrent push will re-add the model,
|
|
30
30
|
# preventing the race where srem fires after a concurrent sadd.
|
|
31
31
|
Buffer.deregister_model(model_name)
|
|
32
32
|
|
|
@@ -44,8 +44,8 @@ module Undertow
|
|
|
44
44
|
config.on_drain.call(model_name, ids, deleted_ids)
|
|
45
45
|
|
|
46
46
|
ActiveSupport::Notifications.instrument('drain.undertow', {
|
|
47
|
-
model:
|
|
48
|
-
ids:
|
|
47
|
+
model: model_name,
|
|
48
|
+
ids: ids,
|
|
49
49
|
deleted_ids: deleted_ids
|
|
50
50
|
})
|
|
51
51
|
rescue StandardError => e
|
data/lib/undertow/dsl.rb
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module Undertow
|
|
4
4
|
# Class-level DSL extended onto ActiveRecord::Base by the Railtie. Any model
|
|
5
5
|
# that calls these methods automatically registers itself with Undertow and
|
|
6
|
-
# gets Trackable behavior wired in at boot
|
|
6
|
+
# gets Trackable behavior wired in at boot, no include needed.
|
|
7
7
|
#
|
|
8
8
|
# class Activity < ApplicationRecord
|
|
9
9
|
# undertow_on_drain ->(model_name, ids, deleted_ids) { ActivityReindexJob.perform_later(ids, deleted_ids) }
|
|
@@ -30,10 +30,10 @@ module Undertow
|
|
|
30
30
|
raise ArgumentError, 'provide exactly one of foreign_key: or resolver:' unless foreign_key.nil? ^ resolver.nil?
|
|
31
31
|
|
|
32
32
|
_undertow_config.dependencies << {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
association: association,
|
|
34
|
+
foreign_key: foreign_key,
|
|
35
|
+
resolver: resolver,
|
|
36
|
+
watched_columns: watched_columns
|
|
37
37
|
}.freeze
|
|
38
38
|
_undertow_ensure_trackable!
|
|
39
39
|
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Undertow
|
|
4
|
+
module Store
|
|
5
|
+
# Abstract base class for Undertow store adapters.
|
|
6
|
+
#
|
|
7
|
+
# Concrete adapters must implement all methods defined here.
|
|
8
|
+
# Buffer delegates all operations to the configured store, so adapters
|
|
9
|
+
# are the only place that knows about the underlying backend.
|
|
10
|
+
class Base
|
|
11
|
+
# Add members to the set at key.
|
|
12
|
+
def add_members(key, members)
|
|
13
|
+
raise NotImplementedError, "#{self.class}#add_members is not implemented"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Remove a single member from the set at key.
|
|
17
|
+
def remove_member(key, member)
|
|
18
|
+
raise NotImplementedError, "#{self.class}#remove_member is not implemented"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Return all members of the set at key.
|
|
22
|
+
def members(key)
|
|
23
|
+
raise NotImplementedError, "#{self.class}#members is not implemented"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Atomically remove and return up to count members from the set at key.
|
|
27
|
+
def pop_members(key, count)
|
|
28
|
+
raise NotImplementedError, "#{self.class}#pop_members is not implemented"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Return the number of members in the set at key.
|
|
32
|
+
def member_count(key)
|
|
33
|
+
raise NotImplementedError, "#{self.class}#member_count is not implemented"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Attempt to acquire a lock at key with the given TTL in seconds.
|
|
37
|
+
# Returns true if the lock was acquired, false if already held.
|
|
38
|
+
def lock_acquire(key, ttl:)
|
|
39
|
+
raise NotImplementedError, "#{self.class}#lock_acquire is not implemented"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Release the lock at key.
|
|
43
|
+
def lock_release(key)
|
|
44
|
+
raise NotImplementedError, "#{self.class}#lock_release is not implemented"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'set'
|
|
4
|
+
|
|
5
|
+
module Undertow
|
|
6
|
+
module Store
|
|
7
|
+
# Store adapter backed by in-process memory.
|
|
8
|
+
#
|
|
9
|
+
# Uses Mutex-protected Ruby Sets for thread safety. Intended for use in
|
|
10
|
+
# test environments and single-process development setups.
|
|
11
|
+
#
|
|
12
|
+
# Lock operations are no-ops, there is no scheduler race in a single process.
|
|
13
|
+
#
|
|
14
|
+
# Undertow.configure do |c|
|
|
15
|
+
# c.store = Undertow::Store::MemoryStore.new
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
# WARNING: State is not shared across processes. Do not use in multi-process
|
|
19
|
+
# or multi-dyno deployments.
|
|
20
|
+
class MemoryStore < Base
|
|
21
|
+
def initialize
|
|
22
|
+
super
|
|
23
|
+
@sets = Hash.new { |h, k| h[k] = Set.new }
|
|
24
|
+
@mutex = Mutex.new
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def add_members(key, members)
|
|
28
|
+
@mutex.synchronize { @sets[key].merge(Array(members)) }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def remove_member(key, member)
|
|
32
|
+
@mutex.synchronize { @sets[key].delete(member) }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def members(key)
|
|
36
|
+
@mutex.synchronize { @sets[key].to_a }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def pop_members(key, count)
|
|
40
|
+
@mutex.synchronize do
|
|
41
|
+
members = @sets[key].first(count)
|
|
42
|
+
members.each { |m| @sets[key].delete(m) }
|
|
43
|
+
members
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def member_count(key)
|
|
48
|
+
@mutex.synchronize { @sets[key].size }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# No-op, single process, no scheduler race possible.
|
|
52
|
+
def lock_acquire(*)
|
|
53
|
+
true
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# No-op.
|
|
57
|
+
def lock_release(key)
|
|
58
|
+
# nothing to do
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Undertow
|
|
4
|
+
module Store
|
|
5
|
+
# Store adapter backed by Redis.
|
|
6
|
+
#
|
|
7
|
+
# Accepts a Redis client or a connection pool (any object responding to #with).
|
|
8
|
+
#
|
|
9
|
+
# Undertow.configure do |c|
|
|
10
|
+
# c.store = Undertow::Store::RedisStore.new(Redis.new(url: ENV['REDIS_URL']))
|
|
11
|
+
# end
|
|
12
|
+
#
|
|
13
|
+
class RedisStore < Base
|
|
14
|
+
def initialize(client)
|
|
15
|
+
super()
|
|
16
|
+
@client = client
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def add_members(key, members)
|
|
20
|
+
with_redis { |r| r.sadd(key, members) }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def remove_member(key, member)
|
|
24
|
+
with_redis { |r| r.srem(key, member) }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def members(key)
|
|
28
|
+
with_redis { |r| r.smembers(key) } || []
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def pop_members(key, count)
|
|
32
|
+
with_redis { |r| r.spop(key, count) } || []
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def member_count(key)
|
|
36
|
+
with_redis { |r| r.scard(key) } || 0
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def lock_acquire(key, ttl:)
|
|
40
|
+
with_redis { |r| r.set(key, '1', nx: true, ex: ttl) } || false
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def lock_release(key)
|
|
44
|
+
with_redis { |r| r.del(key) }
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def with_redis
|
|
50
|
+
if @client.respond_to?(:with)
|
|
51
|
+
@client.with { |conn| yield conn }
|
|
52
|
+
else
|
|
53
|
+
yield @client
|
|
54
|
+
end
|
|
55
|
+
rescue Redis::BaseConnectionError, Redis::CommandError => e
|
|
56
|
+
Rails.logger.error("Undertow: Redis error: #{e.message}") if defined?(Rails)
|
|
57
|
+
nil
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
data/lib/undertow/trackable.rb
CHANGED
|
@@ -11,14 +11,14 @@ module Undertow
|
|
|
11
11
|
|
|
12
12
|
included do
|
|
13
13
|
# Columns listed here suppress self-tracking when they are the *only*
|
|
14
|
-
# things that changed
|
|
14
|
+
# things that changed, prevents feedback loops from columns updated by
|
|
15
15
|
# the drain handler itself.
|
|
16
16
|
class_attribute :_undertow_ignored_columns, default: [], instance_writer: false
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
class_methods do
|
|
20
20
|
# Called by the Railtie after all models/associations are loaded.
|
|
21
|
-
# Idempotent
|
|
21
|
+
# Idempotent, safe to call multiple times (e.g. in reloading environments).
|
|
22
22
|
def register_undertow_callbacks!(config)
|
|
23
23
|
return if @_undertow_callbacks_registered
|
|
24
24
|
|
|
@@ -43,7 +43,7 @@ module Undertow
|
|
|
43
43
|
return unless dep_class
|
|
44
44
|
|
|
45
45
|
root_class = self
|
|
46
|
-
watched = dep[:watched_columns].presence # [] treated same as nil
|
|
46
|
+
watched = dep[:watched_columns].presence # [] treated same as nil, watch all
|
|
47
47
|
|
|
48
48
|
resolver = dep[:resolver] || begin
|
|
49
49
|
fk = dep[:foreign_key]
|
|
@@ -59,20 +59,20 @@ module Undertow
|
|
|
59
59
|
|
|
60
60
|
# Skip create/update callback when watched_columns is set and none changed.
|
|
61
61
|
# Note: saved_changes is empty when touched via belongs_to touch: true (bypasses
|
|
62
|
-
# dirty tracking)
|
|
62
|
+
# dirty tracking), that correctly falls through to skip here.
|
|
63
63
|
dep_class.after_commit on: %i[create update] do
|
|
64
64
|
next if watched && (saved_changes.keys & watched).none?
|
|
65
65
|
|
|
66
66
|
push_pending.call(self)
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
-
# Dep destroyed
|
|
69
|
+
# Dep destroyed, reindex surviving root records. SoftDeletable calls
|
|
70
70
|
# run_callbacks(:destroy), which fires after_destroy, but update_columns does NOT
|
|
71
71
|
# trigger after_commit, so scoping after_commit to [:create, :update] above
|
|
72
72
|
# ensures destroy commits don't double-fire.
|
|
73
73
|
dep_class.after_destroy { push_pending.call(self) }
|
|
74
74
|
|
|
75
|
-
# Dep restored
|
|
75
|
+
# Dep restored, after_restore is the only hook that fires because restore!
|
|
76
76
|
# uses update_columns, bypassing after_commit.
|
|
77
77
|
if dep_class.respond_to?(:after_restore)
|
|
78
78
|
dep_class.after_restore { push_pending.call(self) }
|
data/lib/undertow/version.rb
CHANGED
data/lib/undertow.rb
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'active_support'
|
|
4
3
|
require 'active_record'
|
|
4
|
+
require 'active_support'
|
|
5
5
|
|
|
6
6
|
require_relative 'undertow/version'
|
|
7
7
|
require_relative 'undertow/configuration'
|
|
8
|
+
require_relative 'undertow/store/base'
|
|
9
|
+
require_relative 'undertow/store/redis_store'
|
|
10
|
+
require_relative 'undertow/store/memory_store'
|
|
8
11
|
require_relative 'undertow/registry'
|
|
9
12
|
require_relative 'undertow/buffer'
|
|
10
13
|
require_relative 'undertow/dsl'
|
|
@@ -37,7 +40,7 @@ module Undertow
|
|
|
37
40
|
end
|
|
38
41
|
|
|
39
42
|
# Called from the host application's scheduler on each tick. Checks for
|
|
40
|
-
# pending work, acquires the drain lock, and enqueues DrainJob
|
|
43
|
+
# pending work, acquires the drain lock, and enqueues DrainJob, no other
|
|
41
44
|
# wiring required:
|
|
42
45
|
#
|
|
43
46
|
# every(1.second, 'undertow') { Undertow.tick }
|
data/undertow.gemspec
CHANGED
|
@@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
|
|
|
13
13
|
|
|
14
14
|
spec.metadata = {
|
|
15
15
|
'source_code_uri' => 'https://github.com/nallenscott/undertow',
|
|
16
|
-
'changelog_uri'
|
|
16
|
+
'changelog_uri' => 'https://github.com/nallenscott/undertow/blob/main/CHANGELOG.md',
|
|
17
17
|
'bug_tracker_uri' => 'https://github.com/nallenscott/undertow/issues'
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -24,5 +24,4 @@ Gem::Specification.new do |spec|
|
|
|
24
24
|
spec.add_dependency 'activerecord', '~> 7.0'
|
|
25
25
|
spec.add_dependency 'activesupport', '~> 7.0'
|
|
26
26
|
spec.add_dependency 'activejob', '~> 7.0'
|
|
27
|
-
spec.add_dependency 'redis', '~> 5.0'
|
|
28
27
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: undertow
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Nathan Allen
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-05-06 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activerecord
|
|
@@ -52,20 +52,6 @@ dependencies:
|
|
|
52
52
|
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: '7.0'
|
|
55
|
-
- !ruby/object:Gem::Dependency
|
|
56
|
-
name: redis
|
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
|
58
|
-
requirements:
|
|
59
|
-
- - "~>"
|
|
60
|
-
- !ruby/object:Gem::Version
|
|
61
|
-
version: '5.0'
|
|
62
|
-
type: :runtime
|
|
63
|
-
prerelease: false
|
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
-
requirements:
|
|
66
|
-
- - "~>"
|
|
67
|
-
- !ruby/object:Gem::Version
|
|
68
|
-
version: '5.0'
|
|
69
55
|
description:
|
|
70
56
|
email:
|
|
71
57
|
- hello@nallenscott.com
|
|
@@ -80,6 +66,9 @@ files:
|
|
|
80
66
|
- lib/undertow/dsl.rb
|
|
81
67
|
- lib/undertow/railtie.rb
|
|
82
68
|
- lib/undertow/registry.rb
|
|
69
|
+
- lib/undertow/store/base.rb
|
|
70
|
+
- lib/undertow/store/memory_store.rb
|
|
71
|
+
- lib/undertow/store/redis_store.rb
|
|
83
72
|
- lib/undertow/trackable.rb
|
|
84
73
|
- lib/undertow/version.rb
|
|
85
74
|
- undertow.gemspec
|