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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions