Repository navigation
fix(server): a reset credit's limits refresh when the first read after it fails #34780
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,12 @@ | ||
| /** Instances sharing a login directory share credits; serialize redemptions on that directory. */ | ||
| import type { ProviderConsumeResetCreditOutcome } from "@t3tools/contracts"; | ||
| import type { ProviderConsumeResetCreditOutcome, ServerProvider } from "@t3tools/contracts"; | ||
| import * as Context from "effect/Context"; | ||
| import * as SecureRandom from "effect/crypto/SecureRandom"; | ||
| import * as Effect from "effect/Effect"; | ||
| import * as Layer from "effect/Layer"; | ||
| import type * as PlatformError from "effect/PlatformError"; | ||
| import * as Ref from "effect/Ref"; | ||
| import * as Schedule from "effect/Schedule"; | ||
| import * as Semaphore from "effect/Semaphore"; | ||
|
|
||
| interface AccountRedemptionState { | ||
|
|
@@ -70,6 +71,36 @@ export const make = Effect.gen(function* () { | |
| return { redeem } satisfies ResetCreditCoordinator["Service"]; | ||
| }); | ||
|
|
||
| type UsageSnapshot = Pick<ServerProvider, "usageLimits">; | ||
|
|
||
| /** | ||
| * Re-probe after a redemption; true once a `reset` shows fresh limits. A failed | ||
| * usage read republishes the pre-redemption windows, which are known stale after | ||
| * a reset, so retry briefly instead of leaving them until the periodic check. | ||
| */ | ||
| export const refreshAfterRedemption = Effect.fn("resetCreditCoordinator.refreshAfterRedemption")( | ||
| function* <R>(input: { | ||
| readonly outcome: ProviderConsumeResetCreditOutcome; | ||
| readonly getSnapshot: Effect.Effect<UsageSnapshot>; | ||
| readonly refresh: Effect.Effect<UsageSnapshot, never, R>; | ||
| }) { | ||
| const before = (yield* input.getSnapshot).usageLimits?.checkedAt; | ||
| const confirmed = ({ usageLimits }: UsageSnapshot) => | ||
| input.outcome !== "reset" || | ||
| (usageLimits !== undefined && | ||
| usageLimits.checkedAt !== before && | ||
| usageLimits.unavailable?.reason !== "probeFailed"); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do not treat a failed If Requiring present usage windows in the predicate would reject accounts that have no native usage. Those accounts produce the same snapshot, and the previous inline check accepted them. They would retry and then fail with "could not confirm." Separate a failed config read from a route that does not report usage in
|
||
| return yield* input.refresh.pipe( | ||
| Effect.map(confirmed), | ||
| Effect.repeat({ | ||
| until: (ok) => ok, | ||
| times: 3, | ||
| schedule: Schedule.exponential("1 second"), | ||
| }), | ||
| ); | ||
| }, | ||
| ); | ||
|
|
||
| export const layer = Layer.effect(ResetCreditCoordinator, make); | ||
|
|
||
| export const layerTest = Layer.effect( | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Put refresh confirmation on
ResetCreditCoordinator.refreshAfterRedemptionis an exported server operation outside the existing service. Add it toResetCreditCoordinator["Service"], and have both drivers and its test call the service method. The coding guideline says, “A server capability is a method on a service in its domain folder.” The path instruction likewise says that server capabilities belong in the existing domain service. (raw.githubusercontent.com)Sources: Coding guidelines, Path instructions