// Generating a resource is a job, not a request. Writing a deck takes minutes // — a library search, one or two long model calls, figures — and a browser // holding a request open that long gives up on its own (Firefox at five // minutes, exactly the "NetworkError when attempting to fetch resource" the // user saw while the server carried on and saved the deck anyway). The request // now records what was asked and returns at once; the work runs on the server, // the page polls, and the library updates when a job lands. Several can run at // once, and a reload loses nothing. exports.up = pgm => pgm.sql(` CREATE TABLE IF NOT EXISTS user_resource_jobs ( id SERIAL PRIMARY KEY, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, topic TEXT NOT NULL, kind TEXT NOT NULL, request JSONB NOT NULL DEFAULT '{}'::jsonb, status TEXT NOT NULL DEFAULT 'queued', result JSONB, error TEXT, resource_id INTEGER REFERENCES user_resources(id) ON DELETE SET NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), started_at TIMESTAMPTZ, finished_at TIMESTAMPTZ ); CREATE INDEX IF NOT EXISTS idx_resource_jobs_user_created ON user_resource_jobs (user_id, created_at DESC); `); exports.down = pgm => pgm.sql(` DROP TABLE IF EXISTS user_resource_jobs; `);