stampeded 0.4.0 → 0.4.1
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/stampeded/schema.rb +33 -5
- data/lib/stampeded/version.rb +1 -1
- data/schema/{schema.sql → 0001_init.sql} +6 -21
- data/schema/0002_dedup_key_period.sql +14 -0
- data/schema/0003_dedup_key_separator.sql +17 -0
- data/schema/0004_dedup_key_raw_scope.sql +12 -0
- data/schema/0005_schema_version_guard.sql +9 -0
- metadata +6 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d3ce5382689990aa3c0d7280ec0e86af16f18a7494a1fd96603bd6942c467c4b
|
|
4
|
+
data.tar.gz: 9e055b934cca7b96d9a7b464235d9d6b515937dc9c8d53618e2461a12d4134f4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: aaa523d7d9dd7d567bd1818da6a9c0064b8cc1582f76cb9279ce6f2b2b7c209f75e21aa36185f4e8a0faef2033f1f732d3c48846232f2576ffec25729ad271c4
|
|
7
|
+
data.tar.gz: dbba8d9afc205878ae795aad19953daaabb080c593769c30ab54f2c363f6d06abff8e0c41d7592a9b31e0ebe12c300df86fed9caaa4d6bc7f2de47b499f039e0
|
data/lib/stampeded/schema.rb
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "digest"
|
|
4
|
+
|
|
3
5
|
module Stampeded
|
|
4
6
|
module Schema
|
|
5
|
-
|
|
7
|
+
# Where the daemon's sqlx migrator records what it applied.
|
|
8
|
+
TABLE = "stampeded_migrations"
|
|
6
9
|
|
|
7
10
|
module_function
|
|
8
11
|
|
|
@@ -15,15 +18,40 @@ module Stampeded
|
|
|
15
18
|
raise(Error, "cannot find schema/*.sql (looked in #{candidates.join(", ")})")
|
|
16
19
|
end
|
|
17
20
|
|
|
18
|
-
|
|
19
|
-
|
|
21
|
+
# [version, description, sql] per migration, in order: sqlx's names.
|
|
22
|
+
def migrations
|
|
23
|
+
Dir[File.join(root, "*.sql")].sort.map do |path|
|
|
24
|
+
version, name = File.basename(path, ".sql").split("_", 2)
|
|
25
|
+
[Integer(version, 10), name.tr("_", " "), File.read(path)]
|
|
26
|
+
end
|
|
20
27
|
end
|
|
21
28
|
|
|
29
|
+
def sql = migrations.map(&:last).join("\n")
|
|
30
|
+
|
|
31
|
+
# A fresh install, recorded as sqlx records it, so the daemon's
|
|
32
|
+
# --migrate finds nothing to apply.
|
|
22
33
|
def install!(conn = nil)
|
|
23
34
|
run = lambda do |c|
|
|
24
35
|
c.exec("BEGIN")
|
|
25
36
|
begin
|
|
26
|
-
c.exec(
|
|
37
|
+
c.exec(<<~SQL)
|
|
38
|
+
CREATE TABLE #{TABLE} (
|
|
39
|
+
version BIGINT PRIMARY KEY,
|
|
40
|
+
description TEXT NOT NULL,
|
|
41
|
+
installed_on TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
42
|
+
success BOOLEAN NOT NULL,
|
|
43
|
+
checksum BYTEA NOT NULL,
|
|
44
|
+
execution_time BIGINT NOT NULL
|
|
45
|
+
)
|
|
46
|
+
SQL
|
|
47
|
+
migrations.each do |version, description, sql|
|
|
48
|
+
c.exec(sql)
|
|
49
|
+
c.exec_params(
|
|
50
|
+
"INSERT INTO #{TABLE} (version, description, success, checksum, execution_time) " \
|
|
51
|
+
"VALUES ($1, $2, true, decode($3, 'hex'), 0)",
|
|
52
|
+
[version, description, Digest::SHA384.hexdigest(sql)]
|
|
53
|
+
)
|
|
54
|
+
end
|
|
27
55
|
c.exec("COMMIT")
|
|
28
56
|
rescue StandardError
|
|
29
57
|
c.exec("ROLLBACK")
|
|
@@ -40,7 +68,7 @@ module Stampeded
|
|
|
40
68
|
DROP TABLE IF EXISTS stampeded_cron_occurrences, stampeded_schedules,
|
|
41
69
|
stampeded_queue_policies, stampeded_queue_counts,
|
|
42
70
|
stampeded_jobs, stampeded_workers,
|
|
43
|
-
stampeded_schema CASCADE;
|
|
71
|
+
stampeded_schema, stampeded_migrations CASCADE;
|
|
44
72
|
DO $$
|
|
45
73
|
DECLARE r record;
|
|
46
74
|
BEGIN
|
data/lib/stampeded/version.rb
CHANGED
|
@@ -65,20 +65,15 @@ CREATE TABLE stampeded_jobs (
|
|
|
65
65
|
dedup_period text CHECK (dedup_period IN
|
|
66
66
|
('minute','hour','day','week','month')),
|
|
67
67
|
|
|
68
|
-
-- Scope, period and bucket: buckets of two periods start together (an
|
|
69
|
-
-- hour and its day at midnight UTC), so the period keeps them apart.
|
|
70
|
-
-- Joined as bytea with a raw zero byte: no `text` value can ever decode
|
|
71
|
-
-- to one (chr(0) itself is refused), so a crafted dedup_scope can never
|
|
72
|
-
-- forge the separator and so never forge another row's key.
|
|
73
68
|
dedup_key bytea GENERATED ALWAYS AS (
|
|
74
|
-
sha256(
|
|
75
|
-
dedup_scope
|
|
76
|
-
|
|
69
|
+
sha256((
|
|
70
|
+
dedup_scope || coalesce(
|
|
71
|
+
':' || extract(
|
|
77
72
|
epoch FROM (date_trunc(dedup_period, inserted_at, 'UTC') - to_timestamp(0))
|
|
78
|
-
)::bigint::text
|
|
79
|
-
''
|
|
73
|
+
)::bigint::text,
|
|
74
|
+
''
|
|
80
75
|
)
|
|
81
|
-
)
|
|
76
|
+
)::bytea)
|
|
82
77
|
) STORED,
|
|
83
78
|
|
|
84
79
|
failure_kind text,
|
|
@@ -1052,13 +1047,3 @@ CREATE TABLE stampeded_queue_policies (
|
|
|
1052
1047
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
1053
1048
|
updated_at timestamptz NOT NULL DEFAULT now()
|
|
1054
1049
|
);
|
|
1055
|
-
|
|
1056
|
-
-- Which schema this database holds, one row: `stampeded::schema::migrate`
|
|
1057
|
-
-- upgrades from it and refuses one newer than itself. Raised by each upgrade.
|
|
1058
|
-
CREATE TABLE stampeded_schema (
|
|
1059
|
-
version integer NOT NULL CHECK (version > 0),
|
|
1060
|
-
changed_at timestamptz NOT NULL DEFAULT now()
|
|
1061
|
-
);
|
|
1062
|
-
CREATE UNIQUE INDEX stampeded_schema_one_row ON stampeded_schema ((true));
|
|
1063
|
-
-- Must match schema::VERSION.
|
|
1064
|
-
INSERT INTO stampeded_schema (version) VALUES (3);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
-- Schema 2: the dedup key names its period. Without it, an hourly and a
|
|
2
|
+
-- daily unique job of the same scope shared a key whenever their buckets
|
|
3
|
+
-- started together (every midnight UTC, Mondays, the 1st of a month) and
|
|
4
|
+
-- refused each other. The new key is strictly finer: no row can collide.
|
|
5
|
+
ALTER TABLE stampeded_jobs ALTER COLUMN dedup_key SET EXPRESSION AS (
|
|
6
|
+
sha256((
|
|
7
|
+
dedup_scope || coalesce(
|
|
8
|
+
':' || dedup_period || ':' || extract(
|
|
9
|
+
epoch FROM (date_trunc(dedup_period, inserted_at, 'UTC') - to_timestamp(0))
|
|
10
|
+
)::bigint::text,
|
|
11
|
+
''
|
|
12
|
+
)
|
|
13
|
+
)::bytea)
|
|
14
|
+
);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
-- Schema 3: the dedup key joins scope/period/bucket as bytea with a raw
|
|
2
|
+
-- zero byte. The old ':' join let a crafted dedup_scope (e.g.
|
|
3
|
+
-- 'a:hour:1700000000') forge the exact key of an unrelated periodic job
|
|
4
|
+
-- (scope 'a', period 'hour', that epoch) -- same sha256, same unique index,
|
|
5
|
+
-- wrongly rejected as a duplicate. No `text` value can ever decode to a
|
|
6
|
+
-- zero byte (chr(0) itself is refused by Postgres), so the new separator
|
|
7
|
+
-- can never be forged.
|
|
8
|
+
ALTER TABLE stampeded_jobs ALTER COLUMN dedup_key SET EXPRESSION AS (
|
|
9
|
+
sha256(
|
|
10
|
+
dedup_scope::bytea || '\x00'::bytea || coalesce(
|
|
11
|
+
dedup_period::bytea || '\x00'::bytea || extract(
|
|
12
|
+
epoch FROM (date_trunc(dedup_period, inserted_at, 'UTC') - to_timestamp(0))
|
|
13
|
+
)::bigint::text::bytea,
|
|
14
|
+
''::bytea
|
|
15
|
+
)
|
|
16
|
+
)
|
|
17
|
+
);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
-- Backslashes are doubled so `::bytea` keeps the scope's own bytes instead
|
|
2
|
+
-- of reading escapes: `a` and `\x61` are distinct scopes.
|
|
3
|
+
ALTER TABLE stampeded_jobs ALTER COLUMN dedup_key SET EXPRESSION AS (
|
|
4
|
+
sha256(
|
|
5
|
+
replace(dedup_scope, '\', '\\')::bytea || '\x00'::bytea || coalesce(
|
|
6
|
+
dedup_period::bytea || '\x00'::bytea || extract(
|
|
7
|
+
epoch FROM (date_trunc(dedup_period, inserted_at, 'UTC') - to_timestamp(0))
|
|
8
|
+
)::bigint::text::bytea,
|
|
9
|
+
''::bytea
|
|
10
|
+
)
|
|
11
|
+
)
|
|
12
|
+
);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
-- stampeded 0.4 reads this and refuses a version above 3, rather than
|
|
2
|
+
-- mistaking this database for an unversioned one and rewriting it.
|
|
3
|
+
CREATE TABLE IF NOT EXISTS stampeded_schema (
|
|
4
|
+
version integer NOT NULL CHECK (version > 0),
|
|
5
|
+
changed_at timestamptz NOT NULL DEFAULT now()
|
|
6
|
+
);
|
|
7
|
+
CREATE UNIQUE INDEX IF NOT EXISTS stampeded_schema_one_row ON stampeded_schema ((true));
|
|
8
|
+
DELETE FROM stampeded_schema;
|
|
9
|
+
INSERT INTO stampeded_schema (version) VALUES (5);
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: stampeded
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.4.
|
|
4
|
+
version: 0.4.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Abdelkader Boudih
|
|
@@ -81,7 +81,11 @@ files:
|
|
|
81
81
|
- lib/stampeded/tasks/stampeded.rake
|
|
82
82
|
- lib/stampeded/version.rb
|
|
83
83
|
- lib/stampeded/worker.rb
|
|
84
|
-
- schema/
|
|
84
|
+
- schema/0001_init.sql
|
|
85
|
+
- schema/0002_dedup_key_period.sql
|
|
86
|
+
- schema/0003_dedup_key_separator.sql
|
|
87
|
+
- schema/0004_dedup_key_raw_scope.sql
|
|
88
|
+
- schema/0005_schema_version_guard.sql
|
|
85
89
|
homepage: https://github.com/seuros/stampeded
|
|
86
90
|
licenses:
|
|
87
91
|
- BSD-3-Clause
|