Two scripts for archiving sequencing runs to long-term tape storage, tracking progress via CouchDB.
An async worker that runs in a continuous loop:
- Scan — walks the sequencing directory tree looking for completed runs (indicated by the presence of a sentinel file)
- Register — new runs are added to CouchDB with status
pending - Claim — the worker atomically claims a pending run to prevent other workers from processing it simultaneously
- Archive — the run directory is packed with
tarand symmetrically encrypted with GPG using a randomly generated 256-bit key - Validate — the encrypted archive is test-decrypted to verify integrity
- Secure key — the encryption key is asymmetrically encrypted to a configured GPG recipient and stored in
~/run_keys/, then the plaintext key is deleted - Update status — the CouchDB document is updated to
encrypted
On failure a run is reset to pending for retry. After 3 failed attempts it is marked failed.
A script that picks up runs with status encrypted and uploads them to PDC (tape storage):
- Collect — fetches runs with status
encryptedfrom CouchDB and checks that both the.tar.gpgand.key.gpgfiles exist locally - Claim — sets status to
archivingbefore touching PDC to prevent duplicate uploads on re-runs - Upload — uploads the
.tar.gpgand.key.gpgfiles to PDC usingdsmc, then verifies both are present in PDC - Update status — sets status to
archivedin CouchDB - Clean up — deletes the local
.tar.gpgand.key.gpgfiles
Runs that get stuck in archiving (e.g. due to a failed status update after a successful upload) are skipped on subsequent runs and require manual intervention.
- Python ≥ 3.14
gpgavailable onPATHtaravailable onPATHdsmcavailable onPATH(for PDC uploads)- A running CouchDB instance with the following views:
_design/lookup/_view/pending_runs_design/lookup/_view/encrypted_runs
- The GPG recipient key imported into the worker's keyring
pip install -e .Both scripts read the same YAML config file. The default path is ~/conf/df_archive.yaml, overridable with the -c flag.
statusdb:
username: myuser
password: mypassword
url: url
database: archiving_status
sequencing_path: /data/sequencing # top-level directory; subdirs are per-sequencer (encrypt only)
archive_staging_path: /data/archives # where .tar.gpg and .key files are written
gpg_receiver: user # GPG key ID or email for key encryption (encrypt only)
ignore: # optional: run directory names to skip (encrypt only)
- nosync
- transferring
tar_exclusions: # optional: patterns passed to tar --exclude (encrypt only)
- "Demultiplex*"
- "demux_*"
log_file: /var/log/dataflow_archive.log # optional: write logs to file
log_level: INFO # optional: DEBUG, INFO, WARN, ERROR (default: INFO)sequencing_path/
sequencer_A/
run_001/
.metadata_rsync_exitcode ← sentinel file; run is picked up only when this exists
...
run_002/
...
sequencer_B/
...
# Use the default config path
dataflow_encrypt
# Specify a config file explicitly
dataflow_encrypt -c /path/to/config.yaml| Input | Behaviour |
|---|---|
| Ctrl+C (first) | Graceful — finishes any runs currently in progress, then exits |
| Ctrl+C (second) | Immediate — cancels in-progress tasks, cleans up partial files, then exits |
| SIGTERM | Same as first Ctrl+C |
# Use the default config path
dataflow_archive
# Specify a config file explicitly
dataflow_archive -c /path/to/config.yamlEach run is stored as a document with _id set to the run directory name:
{
"_id": "run_001",
"path": "/data/sequencing/sequencer_A/run_001",
"status": "archived",
"encryption_worker_id": "hostname",
"encryption_failure_count": 0,
"created_at": "2026-04-28T10:00:00+00:00",
"updated_at": "2026-04-28T10:05:00+00:00",
"pdc_archived": "2026-04-28T11:00:00+00:00"
}| Status | Set by | Meaning |
|---|---|---|
pending |
dataflow_encrypt |
Waiting to be processed (or reset after a recoverable failure) |
processing |
dataflow_encrypt |
Currently being encrypted by a worker |
encrypted |
dataflow_encrypt |
Successfully encrypted and validated; ready for PDC upload |
failed |
dataflow_encrypt |
Failed more than 3 times; requires manual intervention |
archiving |
dataflow_archive |
PDC upload claimed; upload in progress or stuck (requires manual check if stale) |
archived |
dataflow_archive |
Successfully uploaded to PDC; local files deleted |
archiving_failed |
dataflow_archive |
Upload to PDC failed; local files NOT deleted |
| File | Location | Description |
|---|---|---|
<run>.tar.gpg |
archive_staging_path/ |
AES-256 symmetrically encrypted tar archive |
<run>.key |
archive_staging_path/ |
Plaintext encryption key (temporary; deleted after key encryption step) |
<run>.key.gpg |
~/run_keys/ |
Encryption key, asymmetrically encrypted to gpg_receiver |
Install dev dependencies:
pip install -e ".[dev]"Run linting:
ruff check .