Files
ystp/migrations/025_storage_object_lifecycle.sql

102 lines
3.1 KiB
SQL

ALTER TABLE tasks
ADD COLUMN deletion_started_at TIMESTAMPTZ,
ADD COLUMN deletion_reason VARCHAR(32);
CREATE INDEX tasks_deletion_pending
ON tasks(deletion_started_at)
WHERE deletion_started_at IS NOT NULL;
CREATE TABLE storage_objects (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
task_id UUID NOT NULL,
task_file_id UUID,
object_kind VARCHAR(32) NOT NULL,
state VARCHAR(20) NOT NULL DEFAULT 'staging',
backend VARCHAR(16) NOT NULL,
storage_endpoint_id UUID REFERENCES storage_endpoints(id) ON DELETE RESTRICT,
object_key TEXT NOT NULL,
storage_etag TEXT,
size_bytes BIGINT,
lease_owner UUID,
lease_until TIMESTAMPTZ,
delete_attempts INTEGER NOT NULL DEFAULT 0,
next_attempt_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
last_error TEXT,
published_at TIMESTAMPTZ,
deleted_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT storage_objects_kind_check
CHECK (object_kind IN ('result', 'zip_attempt', 'input', 'input_dir', 'legacy_zip')),
CONSTRAINT storage_objects_state_check
CHECK (state IN ('staging', 'published', 'delete_pending', 'deleted')),
CONSTRAINT storage_objects_backend_check
CHECK (backend IN ('s3', 'local', 'local_dir')),
CONSTRAINT storage_objects_attempts_check
CHECK (delete_attempts >= 0),
CONSTRAINT storage_objects_size_check
CHECK (size_bytes IS NULL OR size_bytes >= 0),
CONSTRAINT storage_objects_endpoint_check
CHECK (
(backend = 's3' AND storage_endpoint_id IS NOT NULL)
OR (backend IN ('local', 'local_dir') AND storage_endpoint_id IS NULL)
),
CONSTRAINT storage_objects_lease_pair_check
CHECK ((lease_owner IS NULL) = (lease_until IS NULL))
);
CREATE UNIQUE INDEX storage_objects_locator_unique
ON storage_objects(
backend,
COALESCE(storage_endpoint_id, '00000000-0000-0000-0000-000000000000'::uuid),
object_key
);
CREATE INDEX storage_objects_cleanup_ready
ON storage_objects(next_attempt_at, created_at)
WHERE state IN ('staging', 'delete_pending');
CREATE INDEX storage_objects_task
ON storage_objects(task_id, state);
INSERT INTO storage_objects (
task_id, task_file_id, object_kind, state,
backend, storage_endpoint_id, object_key, storage_etag,
size_bytes, published_at
)
SELECT
file.task_id,
file.id,
'result',
'published',
file.storage_backend,
file.storage_endpoint_id,
COALESCE(file.storage_key, file.storage_path),
file.storage_etag,
file.compressed_size,
COALESCE(file.completed_at, file.created_at)
FROM task_files AS file
WHERE file.status = 'completed'
AND COALESCE(file.storage_key, file.storage_path) IS NOT NULL
ON CONFLICT DO NOTHING;
INSERT INTO storage_objects (
task_id, object_kind, state,
backend, storage_endpoint_id, object_key, storage_etag,
size_bytes, published_at
)
SELECT
task.id,
'zip_attempt',
'published',
task.zip_storage_backend,
task.zip_storage_endpoint_id,
task.zip_storage_key,
task.zip_storage_etag,
task.zip_size,
COALESCE(task.completed_at, task.created_at)
FROM tasks AS task
WHERE task.zip_storage_backend IS NOT NULL
AND task.zip_storage_key IS NOT NULL
ON CONFLICT DO NOTHING;