|
@@ -67,8 +67,27 @@ void RetentionService::worker() {
|
|
|
job.from_creation);
|
|
job.from_creation);
|
|
|
const int64_t documents = restamp(own, kNoWorkflowField, job.workflow_id, job.ttl_seconds, job.from_creation);
|
|
const int64_t documents = restamp(own, kNoWorkflowField, job.workflow_id, job.ttl_seconds, job.from_creation);
|
|
|
|
|
|
|
|
- LOG_INFO("Retention: workflow {} restamped to {}s - {} executions, {} documents",
|
|
|
|
|
- job.workflow_id, job.ttl_seconds, executions, documents);
|
|
|
|
|
|
|
+ // Files too, now that a stored file's expiry can be changed after the
|
|
|
|
|
+ // fact and the owning workflow is recorded on it. Both were true only
|
|
|
|
|
+ // from 2.8: before that a file's lifetime was fixed at upload and the
|
|
|
|
|
+ // store could not be asked whose it was, which is why this used to
|
|
|
|
|
+ // report files as out of reach.
|
|
|
|
|
+ //
|
|
|
|
|
+ // Measured from now rather than from creation. The file store answers
|
|
|
|
|
+ // when a file was made only in its own listing, and being a little
|
|
|
|
|
+ // generous with a file whose document has already gone is the harmless
|
|
|
|
|
+ // direction - the sweeper takes it either way.
|
|
|
|
|
+ int64_t files = 0;
|
|
|
|
|
+ auto owned = storage_.listFilesForWorkflow(job.workflow_id);
|
|
|
|
|
+ if (owned.ok()) {
|
|
|
|
|
+ for (const auto& file : owned.value()) {
|
|
|
|
|
+ if (stopping_) break;
|
|
|
|
|
+ if (storage_.setFileTtl(file.id, job.ttl_seconds * 1000).ok()) files++;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ LOG_INFO("Retention: workflow {} restamped to {}s - {} executions, {} documents, {} files",
|
|
|
|
|
+ job.workflow_id, job.ttl_seconds, executions, documents, files);
|
|
|
|
|
|
|
|
if (job.drop_collection_after) {
|
|
if (job.drop_collection_after) {
|
|
|
// The documents are not gone yet - they expire on their own shortly.
|
|
// The documents are not gone yet - they expire on their own shortly.
|
|
@@ -157,6 +176,7 @@ std::optional<storage::Retention> RetentionService::effectiveFor(const nlohmann:
|
|
|
RetentionService::Preview RetentionService::preview(const std::string& workflow_id,
|
|
RetentionService::Preview RetentionService::preview(const std::string& workflow_id,
|
|
|
int64_t ttl_seconds) {
|
|
int64_t ttl_seconds) {
|
|
|
Preview preview;
|
|
Preview preview;
|
|
|
|
|
+ preview.files_reachable = true;
|
|
|
preview.executions =
|
|
preview.executions =
|
|
|
measure(kExecutions, kExecutionWorkflowField, workflow_id, ttl_seconds);
|
|
measure(kExecutions, kExecutionWorkflowField, workflow_id, ttl_seconds);
|
|
|
preview.documents = measure(storage::workflowCollectionName(workflow_id), kNoWorkflowField,
|
|
preview.documents = measure(storage::workflowCollectionName(workflow_id), kNoWorkflowField,
|
|
@@ -237,13 +257,13 @@ int64_t RetentionService::restamp(const std::string& collection,
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // upsert rather than update: only insert and upsert carry a TTL,
|
|
|
|
|
- // and upsert swaps the expiry entry in one locked server-side
|
|
|
|
|
- // step. It preserves _created_at, so a restamped record still
|
|
|
|
|
- // says when it was made - verified against the live database,
|
|
|
|
|
- // because a retention change that quietly re-dated everything
|
|
|
|
|
- // would be worse than the growth it was meant to fix.
|
|
|
|
|
- auto written = storage_.upsert(collection, doc, id, ttl_ms);
|
|
|
|
|
|
|
+ // patchWithTtl moves the expiry and nothing else. The whole
|
|
|
|
|
+ // document used to be read and written back, because before 2.8
|
|
|
|
|
+ // only insert and upsert carried a TTL - so changing one date
|
|
|
|
|
+ // rewrote every field and bumped the version of every execution
|
|
|
|
|
+ // in the collection. An empty patch changes no field at all.
|
|
|
|
|
+ auto written = storage_.patchWithTtl(collection, id, nlohmann::json::object(),
|
|
|
|
|
+ ttl_ms);
|
|
|
if (written.failed()) {
|
|
if (written.failed()) {
|
|
|
LOG_WARN("Retention: could not restamp {}/{} ({})", collection, id,
|
|
LOG_WARN("Retention: could not restamp {}/{} ({})", collection, id,
|
|
|
written.error().message());
|
|
written.error().message());
|