async-background 0.4.4 → 0.5.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/async/background/clock.rb +25 -0
- data/lib/async/background/entry.rb +1 -3
- data/lib/async/background/job.rb +33 -0
- data/lib/async/background/queue/client.rb +38 -12
- data/lib/async/background/queue/notifier.rb +3 -1
- data/lib/async/background/queue/store.rb +41 -31
- data/lib/async/background/runner.rb +23 -22
- data/lib/async/background/version.rb +1 -1
- data/lib/async/background.rb +3 -0
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5959a648b21b8312d1b2d8d566ade149e736b6386eff0cf1fb9acd09801ba748
|
|
4
|
+
data.tar.gz: 839fd36e05ee3ef845ba1f2afaef50a5c996edf9812240a61198cb2f203d0e9a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 408c3267a1acd854448a4dec42d0a3ab30a3ed8e40d40e5c841aca6c29cd2dc3378683ef7c5b305fa419b4fefea80292968efa67e1ff6eb8a4de5d7a5c403e00
|
|
7
|
+
data.tar.gz: 7d7af316122b5208e7adaaf681be8075821936fda225e78def6f8a9b76cf5350e50cd0bf6015888e585c149101c741de2d5f52ba82ffa4aa35734a3d86183511
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Async
|
|
4
|
+
module Background
|
|
5
|
+
# Shared clock helpers used across Runner, Queue::Store, and Queue::Client.
|
|
6
|
+
#
|
|
7
|
+
# monotonic_now — CLOCK_MONOTONIC, for in-process intervals and durations
|
|
8
|
+
# (immune to NTP drift / wall-clock jumps)
|
|
9
|
+
#
|
|
10
|
+
# realtime_now — CLOCK_REALTIME, for persisted timestamps (SQLite run_at,
|
|
11
|
+
# created_at, locked_at) and human-readable metrics
|
|
12
|
+
#
|
|
13
|
+
module Clock
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def monotonic_now
|
|
17
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def realtime_now
|
|
21
|
+
Process.clock_gettime(Process::CLOCK_REALTIME)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
module Async
|
|
4
4
|
module Background
|
|
5
5
|
class Entry
|
|
6
|
-
MIN_SLEEP_TIME = 0.1
|
|
7
|
-
|
|
8
6
|
attr_reader :name, :job_class, :interval, :cron, :timeout
|
|
9
7
|
attr_accessor :next_run_at, :running
|
|
10
8
|
|
|
@@ -25,7 +23,7 @@ module Async
|
|
|
25
23
|
else
|
|
26
24
|
now_wall = Time.now
|
|
27
25
|
wait = cron.next_time(now_wall).to_f - now_wall.to_f
|
|
28
|
-
@next_run_at = monotonic_now + [wait, MIN_SLEEP_TIME].max
|
|
26
|
+
@next_run_at = monotonic_now + [wait, Async::Background::MIN_SLEEP_TIME].max
|
|
29
27
|
end
|
|
30
28
|
end
|
|
31
29
|
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Async
|
|
4
|
+
module Background
|
|
5
|
+
module Job
|
|
6
|
+
def self.included(base)
|
|
7
|
+
base.extend(ClassMethods)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
module ClassMethods
|
|
11
|
+
def perform_now(*args)
|
|
12
|
+
new.perform(*args)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def perform_async(*args)
|
|
16
|
+
Async::Background::Queue.enqueue(self, *args)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def perform_in(delay, *args)
|
|
20
|
+
Async::Background::Queue.enqueue_in(delay, self, *args)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def perform_at(time, *args)
|
|
24
|
+
Async::Background::Queue.enqueue_at(time, self, *args)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def perform(*args)
|
|
29
|
+
raise NotImplementedError, "#{self.class} must implement #perform"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -1,38 +1,64 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative '../clock'
|
|
4
|
+
|
|
3
5
|
module Async
|
|
4
6
|
module Background
|
|
5
7
|
module Queue
|
|
6
|
-
# Usage:
|
|
7
|
-
# Async::Background::Queue.enqueue(SendEmailJob, user_id, "welcome")
|
|
8
|
-
#
|
|
9
8
|
class Client
|
|
9
|
+
include Clock
|
|
10
|
+
|
|
10
11
|
def initialize(store:, notifier: nil)
|
|
11
12
|
@store = store
|
|
12
13
|
@notifier = notifier
|
|
13
14
|
end
|
|
14
15
|
|
|
15
|
-
def push(class_name, args = [])
|
|
16
|
-
id = @store.enqueue(class_name, args)
|
|
16
|
+
def push(class_name, args = [], run_at = nil)
|
|
17
|
+
id = @store.enqueue(class_name, args, run_at)
|
|
17
18
|
@notifier&.notify
|
|
18
19
|
id
|
|
19
20
|
end
|
|
21
|
+
|
|
22
|
+
def push_in(delay, class_name, args = [])
|
|
23
|
+
run_at = realtime_now + delay.to_f
|
|
24
|
+
push(class_name, args, run_at)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def push_at(time, class_name, args = [])
|
|
28
|
+
run_at = time.respond_to?(:to_f) ? time.to_f : time
|
|
29
|
+
push(class_name, args, run_at)
|
|
30
|
+
end
|
|
20
31
|
end
|
|
21
32
|
|
|
22
33
|
class << self
|
|
23
34
|
attr_accessor :default_client
|
|
24
35
|
|
|
25
36
|
def enqueue(job_class, *args)
|
|
37
|
+
ensure_configured!
|
|
38
|
+
default_client.push(resolve_class_name(job_class), args)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def enqueue_in(delay, job_class, *args)
|
|
42
|
+
ensure_configured!
|
|
43
|
+
default_client.push_in(delay, resolve_class_name(job_class), args)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def enqueue_at(time, job_class, *args)
|
|
47
|
+
ensure_configured!
|
|
48
|
+
default_client.push_at(time, resolve_class_name(job_class), args)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def ensure_configured!
|
|
26
54
|
raise "Async::Background::Queue not configured" unless default_client
|
|
55
|
+
end
|
|
27
56
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
raise ArgumentError, "#{job_class} must implement .perform_now" unless job_class.respond_to?(:perform_now)
|
|
32
|
-
class_name = job_class.name
|
|
33
|
-
end
|
|
57
|
+
def resolve_class_name(job_class)
|
|
58
|
+
return job_class if job_class.is_a?(String)
|
|
59
|
+
return job_class.name if job_class.respond_to?(:perform_now)
|
|
34
60
|
|
|
35
|
-
|
|
61
|
+
raise ArgumentError, "#{job_class} must include Async::Background::Job"
|
|
36
62
|
end
|
|
37
63
|
end
|
|
38
64
|
end
|
|
@@ -4,6 +4,8 @@ module Async
|
|
|
4
4
|
module Background
|
|
5
5
|
module Queue
|
|
6
6
|
class Notifier
|
|
7
|
+
IO_ERRORS = [IO::WaitReadable, EOFError, IOError].freeze
|
|
8
|
+
|
|
7
9
|
attr_reader :reader, :writer
|
|
8
10
|
|
|
9
11
|
def initialize
|
|
@@ -51,7 +53,7 @@ module Async
|
|
|
51
53
|
def drain
|
|
52
54
|
loop do
|
|
53
55
|
@reader.read_nonblock(256)
|
|
54
|
-
rescue
|
|
56
|
+
rescue *IO_ERRORS
|
|
55
57
|
break
|
|
56
58
|
end
|
|
57
59
|
nil
|
|
@@ -1,41 +1,50 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'json'
|
|
4
|
+
require_relative '../clock'
|
|
4
5
|
|
|
5
6
|
module Async
|
|
6
7
|
module Background
|
|
7
8
|
module Queue
|
|
8
9
|
class Store
|
|
10
|
+
include Clock
|
|
11
|
+
|
|
9
12
|
SCHEMA = <<~SQL
|
|
13
|
+
PRAGMA auto_vacuum = INCREMENTAL;
|
|
10
14
|
CREATE TABLE IF NOT EXISTS jobs (
|
|
11
15
|
id INTEGER PRIMARY KEY,
|
|
12
16
|
class_name TEXT NOT NULL,
|
|
13
17
|
args TEXT NOT NULL DEFAULT '[]',
|
|
14
18
|
status TEXT NOT NULL DEFAULT 'pending',
|
|
15
19
|
created_at REAL NOT NULL,
|
|
20
|
+
run_at REAL NOT NULL,
|
|
16
21
|
locked_by INTEGER,
|
|
17
22
|
locked_at REAL
|
|
18
23
|
);
|
|
19
|
-
CREATE INDEX IF NOT EXISTS
|
|
24
|
+
CREATE INDEX IF NOT EXISTS idx_jobs_status_run_at_id ON jobs(status, run_at, id);
|
|
20
25
|
SQL
|
|
21
26
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
MMAP_SIZE = 268_435_456
|
|
28
|
+
PRAGMAS = ->(mmap_size) {
|
|
29
|
+
<<~SQL
|
|
30
|
+
PRAGMA journal_mode = WAL;
|
|
31
|
+
PRAGMA synchronous = NORMAL;
|
|
32
|
+
PRAGMA mmap_size = #{mmap_size};
|
|
33
|
+
PRAGMA cache_size = -16000;
|
|
34
|
+
PRAGMA temp_store = MEMORY;
|
|
35
|
+
PRAGMA busy_timeout = 5000;
|
|
36
|
+
PRAGMA journal_size_limit = 67108864;
|
|
37
|
+
SQL
|
|
38
|
+
}.freeze
|
|
31
39
|
|
|
32
40
|
CLEANUP_INTERVAL = 300
|
|
33
41
|
CLEANUP_AGE = 3600
|
|
34
42
|
|
|
35
43
|
attr_reader :path
|
|
36
44
|
|
|
37
|
-
def initialize(path: self.class.default_path)
|
|
45
|
+
def initialize(path: self.class.default_path, mmap: true)
|
|
38
46
|
@path = path
|
|
47
|
+
@mmap = mmap
|
|
39
48
|
@db = nil
|
|
40
49
|
@schema_checked = false
|
|
41
50
|
@last_cleanup_at = nil
|
|
@@ -44,28 +53,36 @@ module Async
|
|
|
44
53
|
def ensure_database!
|
|
45
54
|
require_sqlite3
|
|
46
55
|
db = SQLite3::Database.new(@path)
|
|
47
|
-
db.execute_batch(PRAGMAS)
|
|
56
|
+
db.execute_batch(PRAGMAS.call(@mmap ? MMAP_SIZE : 0))
|
|
48
57
|
db.execute_batch(SCHEMA)
|
|
49
58
|
db.execute("PRAGMA wal_checkpoint(TRUNCATE)")
|
|
50
59
|
db.close
|
|
51
60
|
@schema_checked = true
|
|
52
61
|
end
|
|
53
62
|
|
|
54
|
-
def enqueue(class_name, args = [])
|
|
63
|
+
def enqueue(class_name, args = [], run_at = nil)
|
|
55
64
|
ensure_connection
|
|
56
|
-
|
|
65
|
+
run_at ||= realtime_now
|
|
66
|
+
@enqueue_stmt.execute(class_name, JSON.generate(args), realtime_now, run_at)
|
|
57
67
|
@db.last_insert_row_id
|
|
58
68
|
end
|
|
59
69
|
|
|
60
70
|
def fetch(worker_id)
|
|
61
71
|
ensure_connection
|
|
62
|
-
|
|
72
|
+
now = realtime_now
|
|
73
|
+
@db.execute("BEGIN IMMEDIATE")
|
|
74
|
+
results = @fetch_stmt.execute(worker_id, now, now)
|
|
75
|
+
row = results.first
|
|
76
|
+
@fetch_stmt.reset!
|
|
77
|
+
@db.execute("COMMIT")
|
|
63
78
|
return unless row
|
|
64
79
|
|
|
65
80
|
maybe_cleanup
|
|
66
81
|
{ id: row[0], class_name: row[1], args: JSON.parse(row[2]) }
|
|
82
|
+
rescue
|
|
83
|
+
@db.execute("ROLLBACK") rescue nil
|
|
84
|
+
raise
|
|
67
85
|
end
|
|
68
|
-
|
|
69
86
|
def complete(job_id)
|
|
70
87
|
ensure_connection
|
|
71
88
|
@complete_stmt.execute(job_id)
|
|
@@ -86,7 +103,7 @@ module Async
|
|
|
86
103
|
return unless @db && !@db.closed?
|
|
87
104
|
|
|
88
105
|
finalize_statements
|
|
89
|
-
@db.execute("PRAGMA optimize")
|
|
106
|
+
@db.execute("PRAGMA optimize") rescue nil
|
|
90
107
|
@db.close
|
|
91
108
|
@db = nil
|
|
92
109
|
end
|
|
@@ -111,7 +128,7 @@ module Async
|
|
|
111
128
|
require_sqlite3
|
|
112
129
|
finalize_statements
|
|
113
130
|
@db = SQLite3::Database.new(@path)
|
|
114
|
-
@db.execute_batch(PRAGMAS)
|
|
131
|
+
@db.execute_batch(PRAGMAS.call(@mmap ? MMAP_SIZE : 0))
|
|
115
132
|
|
|
116
133
|
unless @schema_checked
|
|
117
134
|
@db.execute_batch(SCHEMA)
|
|
@@ -124,7 +141,7 @@ module Async
|
|
|
124
141
|
|
|
125
142
|
def prepare_statements
|
|
126
143
|
@enqueue_stmt = @db.prepare(
|
|
127
|
-
"INSERT INTO jobs (class_name, args, created_at) VALUES (?, ?, ?)"
|
|
144
|
+
"INSERT INTO jobs (class_name, args, created_at, run_at) VALUES (?, ?, ?, ?)"
|
|
128
145
|
)
|
|
129
146
|
|
|
130
147
|
@fetch_stmt = @db.prepare(<<~SQL)
|
|
@@ -132,8 +149,8 @@ module Async
|
|
|
132
149
|
SET status = 'running', locked_by = ?, locked_at = ?
|
|
133
150
|
WHERE id = (
|
|
134
151
|
SELECT id FROM jobs
|
|
135
|
-
WHERE status = 'pending'
|
|
136
|
-
ORDER BY id
|
|
152
|
+
WHERE status = 'pending' AND run_at <= ?
|
|
153
|
+
ORDER BY run_at, id
|
|
137
154
|
LIMIT 1
|
|
138
155
|
)
|
|
139
156
|
RETURNING id, class_name, args
|
|
@@ -151,10 +168,10 @@ module Async
|
|
|
151
168
|
end
|
|
152
169
|
|
|
153
170
|
def finalize_statements
|
|
154
|
-
%i[
|
|
155
|
-
stmt = instance_variable_get(name)
|
|
171
|
+
%i[enqueue_stmt fetch_stmt complete_stmt fail_stmt requeue_stmt cleanup_stmt].each do |name|
|
|
172
|
+
stmt = instance_variable_get(:"@#{name}")
|
|
156
173
|
stmt&.close rescue nil
|
|
157
|
-
instance_variable_set(name, nil)
|
|
174
|
+
instance_variable_set(:"@#{name}", nil)
|
|
158
175
|
end
|
|
159
176
|
end
|
|
160
177
|
|
|
@@ -170,13 +187,6 @@ module Async
|
|
|
170
187
|
end
|
|
171
188
|
end
|
|
172
189
|
|
|
173
|
-
def realtime_now
|
|
174
|
-
Process.clock_gettime(Process::CLOCK_REALTIME)
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
def monotonic_now
|
|
178
|
-
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
179
|
-
end
|
|
180
190
|
end
|
|
181
191
|
end
|
|
182
192
|
end
|
|
@@ -7,17 +7,19 @@ module Async
|
|
|
7
7
|
module Background
|
|
8
8
|
class ConfigError < StandardError; end
|
|
9
9
|
|
|
10
|
-
DEFAULT_TIMEOUT
|
|
11
|
-
MIN_SLEEP_TIME
|
|
12
|
-
MAX_JITTER
|
|
10
|
+
DEFAULT_TIMEOUT = 30
|
|
11
|
+
MIN_SLEEP_TIME = 0.1
|
|
12
|
+
MAX_JITTER = 5
|
|
13
13
|
QUEUE_POLL_INTERVAL = 5
|
|
14
14
|
|
|
15
15
|
class Runner
|
|
16
|
-
|
|
16
|
+
include Clock
|
|
17
|
+
|
|
18
|
+
attr_reader :logger, :semaphore, :heap, :worker_index, :total_workers, :shutdown, :metrics, :queue_store
|
|
17
19
|
|
|
18
20
|
def initialize(
|
|
19
21
|
config_path:, job_count: 2, worker_index:, total_workers:,
|
|
20
|
-
queue_notifier: nil, queue_db_path: nil
|
|
22
|
+
queue_notifier: nil, queue_db_path: nil, queue_mmap: true
|
|
21
23
|
)
|
|
22
24
|
@logger = Console.logger
|
|
23
25
|
@worker_index = worker_index
|
|
@@ -31,7 +33,7 @@ module Async
|
|
|
31
33
|
@semaphore = ::Async::Semaphore.new(job_count)
|
|
32
34
|
@heap = build_heap(config_path)
|
|
33
35
|
|
|
34
|
-
setup_queue(queue_notifier, queue_db_path)
|
|
36
|
+
setup_queue(queue_notifier, queue_db_path, queue_mmap)
|
|
35
37
|
end
|
|
36
38
|
|
|
37
39
|
def run
|
|
@@ -53,7 +55,7 @@ module Async
|
|
|
53
55
|
@running = false
|
|
54
56
|
logger.info { "Async::Background: stopping gracefully" }
|
|
55
57
|
shutdown.signal
|
|
56
|
-
@queue_notifier&.notify
|
|
58
|
+
@queue_notifier&.notify
|
|
57
59
|
end
|
|
58
60
|
|
|
59
61
|
def running?
|
|
@@ -62,7 +64,7 @@ module Async
|
|
|
62
64
|
|
|
63
65
|
private
|
|
64
66
|
|
|
65
|
-
def setup_queue(queue_notifier, queue_db_path)
|
|
67
|
+
def setup_queue(queue_notifier, queue_db_path, queue_mmap)
|
|
66
68
|
@listen_queue = false
|
|
67
69
|
return unless queue_notifier
|
|
68
70
|
|
|
@@ -76,7 +78,10 @@ module Async
|
|
|
76
78
|
|
|
77
79
|
@listen_queue = true
|
|
78
80
|
@queue_notifier = queue_notifier
|
|
79
|
-
@queue_store = Queue::Store.new(
|
|
81
|
+
@queue_store = Queue::Store.new(
|
|
82
|
+
path: queue_db_path || Queue::Store.default_path,
|
|
83
|
+
mmap: queue_mmap
|
|
84
|
+
)
|
|
80
85
|
|
|
81
86
|
recovered = @queue_store.recover(worker_index)
|
|
82
87
|
logger.info { "Async::Background queue: recovered #{recovered} stale jobs" } if recovered > 0
|
|
@@ -93,13 +98,13 @@ module Async
|
|
|
93
98
|
job = @queue_store.fetch(worker_index)
|
|
94
99
|
break unless job
|
|
95
100
|
|
|
96
|
-
semaphore.async { run_queue_job(
|
|
101
|
+
semaphore.async { |job_task| run_queue_job(job_task, job) }
|
|
97
102
|
end
|
|
98
103
|
end
|
|
99
104
|
end
|
|
100
105
|
end
|
|
101
106
|
|
|
102
|
-
def run_queue_job(
|
|
107
|
+
def run_queue_job(job_task, job)
|
|
103
108
|
class_name = job[:class_name]
|
|
104
109
|
args = job[:args]
|
|
105
110
|
klass = resolve_job_class(class_name)
|
|
@@ -107,7 +112,7 @@ module Async
|
|
|
107
112
|
metrics.job_started(nil)
|
|
108
113
|
t = monotonic_now
|
|
109
114
|
|
|
110
|
-
|
|
115
|
+
job_task.with_timeout(DEFAULT_TIMEOUT) { klass.perform_now(*args) }
|
|
111
116
|
|
|
112
117
|
duration = monotonic_now - t
|
|
113
118
|
metrics.job_finished(nil, duration)
|
|
@@ -137,7 +142,7 @@ module Async
|
|
|
137
142
|
mod.const_get(name, false)
|
|
138
143
|
end
|
|
139
144
|
|
|
140
|
-
raise ConfigError, "#{class_name} must
|
|
145
|
+
raise ConfigError, "#{class_name} must include Async::Background::Job" unless klass.respond_to?(:perform_now)
|
|
141
146
|
|
|
142
147
|
klass
|
|
143
148
|
end
|
|
@@ -161,8 +166,8 @@ module Async
|
|
|
161
166
|
metrics.job_skipped(entry)
|
|
162
167
|
else
|
|
163
168
|
entry.running = true
|
|
164
|
-
semaphore.async do
|
|
165
|
-
run_job(
|
|
169
|
+
semaphore.async do |job_task|
|
|
170
|
+
run_job(job_task, entry)
|
|
166
171
|
ensure
|
|
167
172
|
entry.running = false
|
|
168
173
|
end
|
|
@@ -249,7 +254,7 @@ module Async
|
|
|
249
254
|
raise ConfigError, "[#{name}] unknown class: #{class_name}"
|
|
250
255
|
end
|
|
251
256
|
|
|
252
|
-
raise ConfigError, "[#{name}] #{class_name} must
|
|
257
|
+
raise ConfigError, "[#{name}] #{class_name} must include Async::Background::Job" unless job_class.respond_to?(:perform_now)
|
|
253
258
|
|
|
254
259
|
interval = config['every']&.then { |v|
|
|
255
260
|
int = v.to_i
|
|
@@ -271,14 +276,10 @@ module Async
|
|
|
271
276
|
}
|
|
272
277
|
end
|
|
273
278
|
|
|
274
|
-
def
|
|
275
|
-
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
276
|
-
end
|
|
277
|
-
|
|
278
|
-
def run_job(task, entry)
|
|
279
|
+
def run_job(job_task, entry)
|
|
279
280
|
metrics.job_started(entry)
|
|
280
281
|
t = monotonic_now
|
|
281
|
-
|
|
282
|
+
job_task.with_timeout(entry.timeout) { entry.job_class.perform_now }
|
|
282
283
|
|
|
283
284
|
duration = monotonic_now - t
|
|
284
285
|
metrics.job_finished(entry, duration)
|
data/lib/async/background.rb
CHANGED
|
@@ -7,7 +7,10 @@ require 'fugit'
|
|
|
7
7
|
require 'tmpdir'
|
|
8
8
|
|
|
9
9
|
require_relative 'background/version'
|
|
10
|
+
require_relative 'background/clock'
|
|
10
11
|
require_relative 'background/min_heap'
|
|
11
12
|
require_relative 'background/entry'
|
|
12
13
|
require_relative 'background/metrics'
|
|
13
14
|
require_relative 'background/runner'
|
|
15
|
+
require_relative 'background/queue/client'
|
|
16
|
+
require_relative 'background/job'
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: async-background
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Roman Hajdarov
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-03-
|
|
11
|
+
date: 2026-03-31 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: async
|
|
@@ -91,7 +91,9 @@ extensions: []
|
|
|
91
91
|
extra_rdoc_files: []
|
|
92
92
|
files:
|
|
93
93
|
- lib/async/background.rb
|
|
94
|
+
- lib/async/background/clock.rb
|
|
94
95
|
- lib/async/background/entry.rb
|
|
96
|
+
- lib/async/background/job.rb
|
|
95
97
|
- lib/async/background/metrics.rb
|
|
96
98
|
- lib/async/background/min_heap.rb
|
|
97
99
|
- lib/async/background/queue/client.rb
|