stampeded 0.3.2-aarch64-linux-gnu → 0.4.1-aarch64-linux-gnu

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: 30ba29fba7862a8c5b8877e8ab64babbc1c39868440dbb9f06d2d15cfd97412f
4
- data.tar.gz: 948af6558ab6a9480dd147f3c75d242e4965cd0ff22589e7b3d5afab4ce3aa2b
3
+ metadata.gz: 6fc124e857302980de58695706ba4e80f94531bb21426c8c463565be81eddb7e
4
+ data.tar.gz: cee51f4df6c47377410b789a98156ca6eaa7b3379f818c40a2873385b9832c74
5
5
  SHA512:
6
- metadata.gz: 8afb5700428b6820fc2e7f04e0c9662cfa25603fea90978684395993d5ac643e28c7a68e3bb53a347cdb6edd11e4ce68462210b9e4cac06f7561e70040e2fdff
7
- data.tar.gz: 21c220abe7c5167325ae2d1b95ced35686152804498706b5fe965c09aab19128abf5068cd5600939aaad74aaa91d49e63d2b73cf4666ff9456af95d491419628
6
+ metadata.gz: c4d9554471d8829b2908ce9010b95991631b2e1e518774fe1f0133b7c7904e78732edb03c782f749c36b8249f1d21beefad4e16353e1c4de328258739b0e5bf1
7
+ data.tar.gz: 7d19ae8792459990eb3f20b752f694ce1c5378ff1e27d297c5886128c1f509e6be014fe04b3394b951970f4bc125feea80018eb655c4ca34145f81f2b71cbfe8
@@ -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
- FILES = %w[schema.sql].freeze
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
- def sql
19
- FILES.map { |f| File.read(File.join(root, f)) }.join("\n")
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(sql)
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")
@@ -39,7 +67,8 @@ module Stampeded
39
67
  c.exec(<<~SQL)
40
68
  DROP TABLE IF EXISTS stampeded_cron_occurrences, stampeded_schedules,
41
69
  stampeded_queue_policies, stampeded_queue_counts,
42
- stampeded_jobs, stampeded_workers CASCADE;
70
+ stampeded_jobs, stampeded_workers,
71
+ stampeded_schema, stampeded_migrations CASCADE;
43
72
  DO $$
44
73
  DECLARE r record;
45
74
  BEGIN
@@ -22,10 +22,11 @@ namespace :stampeded do
22
22
  worker.run
23
23
  end
24
24
 
25
- desc "Run the daemon (scheduler, reaper, pruner, dashboard). Not the worker."
25
+ desc "Run the daemon (scheduler, reaper, pruner, dashboard). Not the worker. Upgrades the schema first."
26
26
  task daemon: :environment do
27
27
  require "stampeded/daemon"
28
- args = ["--no-worker", *ENV["STAMPEDED_ARGS"].to_s.split]
28
+ # --migrate is safe on every start: it upgrades an older schema in place.
29
+ args = ["--no-worker", "--migrate", *ENV["STAMPEDED_ARGS"].to_s.split]
29
30
  Stampeded::Daemon.exec!(*args, env: { "STAMPEDED_DATABASE_URL" => Stampeded.database_url_for_daemon })
30
31
  end
31
32
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Stampeded
4
- VERSION = "0.3.2" # x-release-please-version
4
+ VERSION = "0.4.1" # x-release-please-version
5
5
  end
Binary file
data/libexec/stampeded CHANGED
Binary file
@@ -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.3.2
4
+ version: 0.4.1
5
5
  platform: aarch64-linux-gnu
6
6
  authors:
7
7
  - Abdelkader Boudih
@@ -83,7 +83,11 @@ files:
83
83
  - lib/stampeded/worker.rb
84
84
  - libexec/libstampeded_ffi.so
85
85
  - libexec/stampeded
86
- - schema/schema.sql
86
+ - schema/0001_init.sql
87
+ - schema/0002_dedup_key_period.sql
88
+ - schema/0003_dedup_key_separator.sql
89
+ - schema/0004_dedup_key_raw_scope.sql
90
+ - schema/0005_schema_version_guard.sql
87
91
  homepage: https://github.com/seuros/stampeded
88
92
  licenses:
89
93
  - BSD-3-Clause
File without changes