I'm building operator tooling that needs to answer "which apps have not been refreshed recently?" — e.g. a policy that every app must be re-pushed or restaged every 60–90 days (stack rollovers, base-image/CVE hygiene). I went looking for the right field, read through the model/action code, and I'm not sure a good one exists. I'd like to know what you'd recommend, and whether there's appetite for exposing one.
What I found
(line refs at current main, a756779)
apps.updated_at bumps on any write to the apps row — the timestamps plugin is global (lib/cloud_controller/db.rb:115), and the row is written by rename, env-var changes (app_patch_environment_variables.rb:18), start/stop (app_start.rb:15, app_stop.rb:10), per-app feature toggles, and even metadata-only PATCHes (v3 AppUpdate calls bare app.save, app_update.rb:30). It also bumps on every successful push/restage via current-droplet assignment (app_assign_droplet.rb:20), so it can prove an app is stale but never that it's fresh.
v2 had exactly this concept: package_updated_at, presented as the newest package's created_at (process_model.rb:214-216). v3 dropped it, and a package timestamp misses restages anyway (restage reuses latest_package).
Per-operation, what actually moves:
| Operation |
package |
build |
droplet |
apps.updated_at |
| push |
new |
new |
new |
bumps (droplet assign) |
| restage |
— |
new |
new |
bumps (droplet assign) |
| rename / env-var / start / stop |
— |
— |
— |
bumps |
| scale |
— |
— |
— |
— (processes row only) |
There is no staged_at/uploaded_at anywhere in the schema; staging start is implicitly builds.created_at and staging completion is implicitly the droplet row's birth (stagings_controller.rb:136).
Candidates and their problems
apps.updated_at — noisy, as above.
- newest
package.created_at — the v2 definition; misses restages.
- newest
build.created_at — counts staging attempts, including failures (row exists at staging start).
- current droplet's
created_at — moves backward on revision rollback / deployment cancel (deployment_cancel.rb:17) since an old droplet becomes current again.
- newest STAGED droplet's
created_at — my current pick: only exists when staging succeeded, covers push and restage, works for docker lifecycle. Problems: DropletCopy mints a STAGED droplet without any staging, so a copy looks like a refresh; and there's no per-app field, so reading it at list scale means batched /v3/droplets?app_guids=…&states=STAGED&order_by=-created_at joins.
revisions.created_at / deployments.created_at — not universal (revisions per-app toggleable with dedup, deployments only for rolling/canary).
The question
Is there a field I've missed that means "last successful push or restage"? If not, which of the above would you consider canonical — and would a presented field (a v3 successor to package_updated_at, e.g. droplet-based) be a reasonable proposal?
I'm building operator tooling that needs to answer "which apps have not been refreshed recently?" — e.g. a policy that every app must be re-pushed or restaged every 60–90 days (stack rollovers, base-image/CVE hygiene). I went looking for the right field, read through the model/action code, and I'm not sure a good one exists. I'd like to know what you'd recommend, and whether there's appetite for exposing one.
What I found
(line refs at current main, a756779)
apps.updated_atbumps on any write to the apps row — the timestamps plugin is global (lib/cloud_controller/db.rb:115), and the row is written by rename, env-var changes (app_patch_environment_variables.rb:18), start/stop (app_start.rb:15,app_stop.rb:10), per-app feature toggles, and even metadata-only PATCHes (v3AppUpdatecalls bareapp.save,app_update.rb:30). It also bumps on every successful push/restage via current-droplet assignment (app_assign_droplet.rb:20), so it can prove an app is stale but never that it's fresh.v2 had exactly this concept:
package_updated_at, presented as the newest package'screated_at(process_model.rb:214-216). v3 dropped it, and a package timestamp misses restages anyway (restage reuseslatest_package).Per-operation, what actually moves:
There is no
staged_at/uploaded_atanywhere in the schema; staging start is implicitlybuilds.created_atand staging completion is implicitly the droplet row's birth (stagings_controller.rb:136).Candidates and their problems
apps.updated_at— noisy, as above.package.created_at— the v2 definition; misses restages.build.created_at— counts staging attempts, including failures (row exists at staging start).created_at— moves backward on revision rollback / deployment cancel (deployment_cancel.rb:17) since an old droplet becomes current again.created_at— my current pick: only exists when staging succeeded, covers push and restage, works for docker lifecycle. Problems:DropletCopymints a STAGED droplet without any staging, so a copy looks like a refresh; and there's no per-app field, so reading it at list scale means batched/v3/droplets?app_guids=…&states=STAGED&order_by=-created_atjoins.revisions.created_at/deployments.created_at— not universal (revisions per-app toggleable with dedup, deployments only for rolling/canary).The question
Is there a field I've missed that means "last successful push or restage"? If not, which of the above would you consider canonical — and would a presented field (a v3 successor to
package_updated_at, e.g. droplet-based) be a reasonable proposal?