Skip to content

PayG keepAlive=false boxes not auto-pausing at documented 1h idle timeout .. observed 2h+ still idle #161

Description

@shtefcs

Summary

Pay-As-You-Go boxes with keepAlive: false are not auto-pausing at the documented 1-hour idle timeout. We have empirical data of status: "idle" boxes still alive 120+ minutes after their last activity, with no automatic transition to paused. The docs at /docs/box/overall/pricing.md (and /docs/box/overall/how-it-works.md) state PayG idle timeout is "1 hour", the actual observed behavior is at least 2 hours, possibly longer.

This is not blocking us (keepAlive: false idle boxes accrue essentially zero compute cost regardless), but the docs/reality mismatch caused us several hours of confusion while investigating.

Reproduction

Test 1, POLLED box (Box.list every 5 minutes, in case polling is the issue):

const box = await Box.create({ runtime: "node", apiKey, keepAlive: false });
await box.exec.command("echo started"); // single command to confirm box is responsive

// Poll via Box.list (which per #105 should NOT reset the idle timer)
for (let i = 1; i <= 24; i++) {
  await new Promise(r => setTimeout(r, 5 * 60_000));
  const all = await Box.list({ apiKey });
  const me = all.find(b => b.id === box.id);
  console.log(`t=${i*5}min status=${me?.status} last_activity=${me?.last_activity_at}`);
}

Observed: status stays "idle" for the full 120 minutes. last_activity_at is the initial echo and never updates from the Box.list polls (consistent with #105 reply, Box.list does NOT count as activity). The test script terminates without ever observing a transition to paused.

Test 2, UNTOUCHED box (zero polling, single direct GET after 60+ min):

const box = await Box.create({ runtime: "node", apiKey, keepAlive: false });
await box.exec.command("echo started");
// Wait 60+ minutes, then a single direct HTTP GET to verify state
const res = await fetch(`https://us-east-1.box.upstash.com/v2/box/${box.id}`, { headers: { "X-Box-Api-Key": apiKey } });
const data = await res.json();
console.log(data.status, "alive_min:", (Date.now()/1000 - data.created_at)/60);

Observed at t=60+ min: status: "idle", last_activity_at unchanged at the initial echo, keep_alive field absent (so keepAlive is false as expected).

Behavior summary

Test After 5 min After 30 min After 60 min After 120 min
Polled box (Box.list every 5 min) idle idle idle idle
Untouched box (no polls at all) idle idle idle (still being measured) n/a

Per maintainer reply on #105, the activities that reset the idle timer are: box.exec.command, box.files.*, git operations through the Box API, SSH sessions, scheduled runs. Box.list and GET /v2/box/{id} are not listed. We verified last_activity_at stays unchanged across our polls, so the timer is in fact not being reset, yet the box doesn't auto-pause within the documented 1-hour window.

What we expected

Per /docs/box/overall/pricing.md:

Pay as You Go idle timeout: "1 hour"

Per /docs/box/overall/how-it-works.md:

"If a box sits idle with no active commands, it automatically transitions to Paused after an idle timeout."

We expected the polled and untouched boxes to transition to paused around the 60-minute mark.

Suggested fixes

Either:

  1. Update the docs to reflect the actual auto-pause timing on PayG (whatever it actually is, appears to be 2+ hours).
  2. Or, if 1 hour is the intended target, audit why auto-pause is not firing in this account.

Environment

  • @upstash/box: 0.4.1
  • Node.js: 20.19
  • Box runtime: node, size small
  • Account: PayG plan, stefan@vanila.io
  • Test box IDs (already cleaned up): working-shrew-01354, neat-hornet-89278

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions