Loading
feat: #3636593 Add Drush commands to create and cancel archive jobs
Closes https://www.drupal.org/project/earkiv/issues/3636593
What this changes
drush earkiv:create
- Creates a job with the default archiver, storage and their default settings from
earkiv.settings. - Options override the settings:
--url,--connections,--sitemap(--sitemap=0turns it off),--excludeand--start-url(repeatable, replace the defaults),--storage-path,--archiver,--storage. - The settings are validated and normalised by the plugin itself (
buildConfigurationForm(),validateConfigurationForm(),submitConfigurationForm()with aFormState), so the rules are the same as in the form. Settings that are not given get the form default. --processcreates and stores the new job right away, under the processing lock, retrying failed steps like cron. Other queued jobs are not touched. If another process holds the lock, the job is left for the nextearkiv:process.
drush earkiv:cancel ID
- New status
ArchiveStatusEnum::CANCELLED("Cancelled"). Cancelled jobs are never picked up again. - A running job:
HTTrackCommands::waitFor()checks the status withloadUnchanged()every 5 seconds. When the job is cancelled (or deleted) it stops HTTrack or tar and cleans up. The command waits up to 15 seconds for the process to confirm through the progress record. This also works when the job runs on another web server. - If no process confirms, it is assumed dead: the command cleans up itself and releases the lock. The lock API cannot release a lock held by another process, so with the database lock backend the row is deleted from
semaphore. (Thelockservice is a proxy class, so this checks for the table instead ofinstanceof DatabaseLockBackend.) - A job that is not running is cleaned up directly. A job being moved to storage cannot be cancelled, so the stored archive is never half copied.
- Clean-up is a new
cancel()method onEArkivDrushCommandsInterface. For HTTrack it removeshttrack_ID, anyearkiv_ID_*.tar.gzin the temporary directory and a file entity that still points totemporary://. Local storage has nothing to clean up.
Other
EArkivCommands::processJob()processes one step of a given job;earkiv:processandearkiv:create --processboth use it. The job is reloaded afterwards, so a cancellation is recorded and logged.ArchiveProgress::get()can bypass the static State cache, needed to see the confirmation from the other process.- README: documents both commands.
Testing
In DDEV:
earkiv:createwith defaults, and with all options: the stored settings match, normalised like the form (integer connections, one pattern per line). Invalid start URL and unknown plugin are rejected with the plugin message.earkiv:create --processon a small site section: both steps ran, job ended as Done.- Cancel a new job: Cancelled; cancelling again reports it as finished; unknown ID is rejected.
- Cancel a running crawl: the running process stopped HTTrack and cleaned up, the command got the confirmation after 7 s. No HTTrack process, working directory or lock left.
- Kill Drush and HTTrack with SIGKILL, then cancel: no confirmation, the command cleaned up after 15 s and removed the stale lock (1 row before, 0 after).
- Cancel a job waiting for storage: the temporary archive and its file entity were removed, the file reference cleared.
Notes for reviewers
- If the process running a job died but HTTrack itself is still running (an orphan),
earkiv:cancelremoves the working directory but does not kill HTTrack, since it cannot know which process belongs to the job on which server. --connectionsis validated by the plugin, which does not check the form#max; values above 32 are capped when the crawl starts.
AI-Generated: Yes (Used Claude Code to write the code changes, run the tests in DDEV and draft this description.)