Repository navigation
Conversation
After a reboot, migration or restart the platform seeds the new container with the `APIFY_CHARGED_ACTOR_EVENT_COUNTS` recorded when the run started, so the charging manager began from zero charged events and allowed a fresh `max_total_charge_usd` budget. The charging manager now persists its charged event counts to the default key-value store under `__ACTOR_CHARGING_STATE` on every `PERSIST_STATE` event and right before `Actor.reboot()` calls the API, writing only when a charge happened since the last write. A container that starts more than 60 seconds after the run started reads the record and takes the persisted count of each event where it is higher than the platform's. A prompt first start makes no extra request. A record of another run, a malformed one, or a failed read is logged and ignored. Closes #1209 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ocuAKQTqReMDTjXCUTnKP
…them Replaces the key-value store persistence with a read of the run through the API, which needs no writes during the run, no new record, and no reboot hook, and also covers crash restarts. A pay-per-event run on the platform whose pricing has at least one event the SDK can charge, and whose container starts more than 60 seconds after the run started, reads the run and takes the current count of each event where it is higher than the env var's. A prompt first start, a run without SDK-chargeable events, and a local run make no extra request. A failed read is logged and the env var's counts are kept. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ocuAKQTqReMDTjXCUTnKP
…tart A reboot restarts the container in about a second, so a restart cannot be told apart from a first start by the time elapsed since the run started. The time threshold is dropped, and every platform run with a pay-per-event pricing that has at least one event the SDK can charge reads the run at start and takes the current count of each event where it is higher than the env var's. Runs without SDK-chargeable events and local runs make no extra request. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ocuAKQTqReMDTjXCUTnKP
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1218 +/- ##
==========================================
+ Coverage 93.42% 93.43% +0.01%
==========================================
Files 54 54
Lines 3771 3809 +38
==========================================
+ Hits 3523 3559 +36
- Misses 248 250 +2
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
The run is read before the first charge or budgeted push of a container instead of at init, so the platform has time to record the last charges of a previous container, and a run that never charges makes no request. Until then, the synchronous methods report the counts the run started with. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ocuAKQTqReMDTjXCUTnKP
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ocuAKQTqReMDTjXCUTnKP
`_fetch_pricing_info` reports whether the counts were read from the run, and `__aenter__` records it, so the loader has no side effect on the manager. The chargeable-run check uses the pricing already loaded. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ocuAKQTqReMDTjXCUTnKP
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ocuAKQTqReMDTjXCUTnKP
b0a6cd8 to
805e5fd
Compare
…ed counts Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ocuAKQTqReMDTjXCUTnKP
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ocuAKQTqReMDTjXCUTnKP
The charge lock brings the counts up to date the first time it is taken, so neither `charge` nor the push path needs to know about the refresh. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ocuAKQTqReMDTjXCUTnKP
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ocuAKQTqReMDTjXCUTnKP
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ocuAKQTqReMDTjXCUTnKP
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ocuAKQTqReMDTjXCUTnKP
apify-factory
left a comment
There was a problem hiding this comment.
Looks good, just one note.
🏭 Factory review — ℹ️ not auto-approved
This change was reviewed but cannot be auto-approved: a gate failed, so the review cannot end in an approval.
| check | result |
|---|---|
| Static gates | ❌ 14/16 — pr-open-and-ready, deny-globs |
| Review findings | ❌ not clean |
| Reviewer escalation | ❌ Changes pay-per-event charging limit accounting (money) and adds an API request to the charge path on platform runs. |
Juror 1 — claude-sonnet-5-5, adversarial |
⏭️ skipped — a gate failed |
Why it was not auto-approved
Failed gates:
pr-open-and-ready: PR is a draftdeny-globs: src/apify/_charging.py matches src/apify/_charging.py
The comments above are the review itself; this section only explains the approval decision. Push a change and request @apify-factory again to re-run it, or ask a human to review.
Reviewed 896e79144 · workflow run
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ocuAKQTqReMDTjXCUTnKP
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ocuAKQTqReMDTjXCUTnKP
…atform" This reverts commit 9080b39.
|
Hmm, platform's eventual consistency is too slow for this again :( , probably we will have to track it again ourselves |
After a reboot, migration or restart, the platform seeds the new container with the charged event counts recorded when the run started, so the charging manager began from a fresh
max_total_charge_usdbudget. The SDK now reads the run before its first charge and continues from what was already charged.charge()or budgetedpush_data()and updates the charge info from API.Closes: #1209