### Run Region-Placer Locally Source: https://github.com/lambrospetrou/durable-utils/blob/main/examples/region-placer/README.md Navigate to the region-placer example directory and run the development server. This command starts the local instance for testing. ```sh cd examples/region-placer npm run dev ``` -------------------------------- ### Build durable-utils Library Source: https://github.com/lambrospetrou/durable-utils/blob/main/examples/region-placer/README.md Build the durable-utils library locally to make it usable by the example. This command should be run from the example directory. ```sh cd ../../ && npm run npm:publish:dryrun ``` -------------------------------- ### Install durable-utils Source: https://github.com/lambrospetrou/durable-utils/blob/main/README.md Install the durable-utils package using npm. ```sh npm install durable-utils ``` -------------------------------- ### SQLite Schema Migrations Example Source: https://github.com/lambrospetrou/durable-utils/blob/main/README.md Example of how to use SQLSchemaMigrations within a Durable Object class to manage SQLite schema changes. Ensure migrations are run before accessing SQLite. ```javascript import { SQLSchemaMigration, SQLSchemaMigrations, } from 'durable-utils/sql-migrations'; // Example migrations. const Migrations: SQLSchemaMigration[] = [ { idMonotonicInc: 1, description: 'initial version', sql: ` CREATE TABLE IF NOT EXISTS tenant_info( tenantId TEXT PRIMARY KEY, dataJson TEXT ); CREATE TABLE IF NOT EXISTS wikis ( wikiId TEXT PRIMARY KEY, tenantId TEXT, name TEXT, wikiType TEXT ); `, }, { idMonotonicInc: 2, description: 'add timestamp column to wikis', sql: ` ALTER TABLE wikis ADD createdAtMs INTEGER; `, }, ]; export class TenantDO extends DurableObject { env: CfEnv; sql: SqlStorage; _migrations: SQLSchemaMigrations; constructor(ctx: DurableObjectState, env: CfEnv) { super(ctx, env); this.env = env; this.sql = ctx.storage.sql; this._migrations = new SQLSchemaMigrations({ doStorage: ctx.storage, migrations: Migrations, }); // You can run your migrations in the constructor if you are certain // that all requests incoming to your Durable Object (DO) are legit. // If you want to avoid writing to storage and incurring charges when // any request is processed by your DO run them right before you need them // as seen inside the `operationThatNeedsSQLite()` function below. // // ctx.blockConcurrencyWhile(async () => { // await this._migrations.runAll(); // }); } async operationThatNeedsSQLite() { // Always run your migrations before accessing SQLite. // If they already ran, it returns immediately without overhead. await this._migrations.runAll(); // Normal SQLite calls. return this.sql.exec("SELECT * FROM wikis;").toArray(); } } ``` -------------------------------- ### Get Durable Object Stub by Name Source: https://github.com/lambrospetrou/durable-utils/blob/main/README.md Creates a Durable Object stub from a string name using `stubByName`. This utility combines `idFromName` and `get` operations. ```javascript import { stubByName } from "durable-utils/do-utils"; const stub = stubByName(env.MY_DURABLE_OBJECT, "instance-1"); ``` -------------------------------- ### Call Durable Object Methods with Static Sharding Source: https://github.com/lambrospetrou/durable-utils/blob/main/README.md Demonstrates how to call methods on Durable Objects using static sharding. Use `one` to query a specific shard, `all` to query all shards and collect results, `tryAll` to collect results or errors without throwing, and `trySome` to query a subset of shards. ```javascript import { StaticShardedDO } from "durable-utils/do-sharding"; const sdo = new StaticShardedDO(env.DO_ABC, { numShards: 11, concurrency: 6 }); // Query only the shard that handles the given partition key. const partitionKey = "some-resource-ID-here" const resultOfActionA = await sdo.one(partitionKey, async (stub, _shard) => { return await stub.actionA(); }); // Query all 11 shards. // Get their results in an array, or fail with the first error thrown. const resultsOfActionA = await sdo.all(async (stub, _shard) => { return await stub.actionA(); }); // Query all 11 shards. // Get their results or their errors without throwing. const resultsList = await sdo.tryAll(async (stub, shard) => { return await stub.actionA(); }); const failed = resultsList.filter(r => !r.ok); const worked = resultsList.filter(r => r.ok); // Query only the even shards out of the 11. // Get their results or their errors without throwing. const resultsList = await sdo.trySome(async (stub, shard) => { return await stub.actionA(); }, { filterFn: (shard) => shard % 2 === 0, }); // Automatically retry failed shards up to a total of 3 attempts. const resultsList = await sdo.trySome(async (stub, shard) => { return await stub.actionA(); }, { filterFn: (_shard) => true, shouldRetry: (_error, attempt, _shard) => attempt < 4; }); ``` -------------------------------- ### tryN(n, fn, options) Source: https://github.com/lambrospetrou/durable-utils/blob/main/README.md Executes a function with a maximum number of retry attempts, implementing exponential backoff with full jitter. It's suitable for operations where a fixed number of retries is desired. ```APIDOC ## tryN(n, fn, options) ### Description Executes a function with retry logic, implementing exponential backoff with full jitter. This function is useful when you want to retry an operation a specific number of times. ### Parameters #### Parameters - **n** (number) - Required - Maximum number of attempts. - **fn** (function) - Required - Async function to execute. It receives the current attempt number and returns a value of type `T`. - **options** (object) - Optional - Configuration object for retry behavior. - **baseDelayMs** (number) - Optional - Base delay for exponential backoff (default: 100ms). - **maxDelayMs** (number) - Optional - Maximum delay between retries (default: 3000ms). - **isRetryable** (function) - Optional - Function that determines if an error should trigger a retry. - **verbose** (boolean) - Optional - Enable logging of retry attempts. ### Retry Delay Calculation The retry delay is calculated using the "Full Jitter" approach: `random_between(0, min(2^attempt * baseDelayMs, maxDelayMs))`. ``` -------------------------------- ### Execute Function with Fixed Retries Source: https://github.com/lambrospetrou/durable-utils/blob/main/README.md Use `tryN` to execute an async function a fixed number of times with exponential backoff and full jitter. It's suitable for operations where a maximum number of retries is known. ```javascript import { tryN } from "durable-utils/retries"; await tryN( 3, async (_attempt) => fetch(url) ); ``` -------------------------------- ### tryWhile(fn, isRetryable, options) Source: https://github.com/lambrospetrou/durable-utils/blob/main/README.md Executes a function repeatedly as long as a condition is met, implementing exponential backoff with full jitter. This is ideal for operations that should continue retrying until successful or a specific condition is no longer met. ```APIDOC ## tryWhile(fn, isRetryable, options) ### Description Executes a function with retry logic, implementing exponential backoff with full jitter. This function retries as long as the `isRetryable` condition is met, making it suitable for operations that need to continue until a specific state is reached or an unrecoverable error occurs. ### Parameters #### Parameters - **fn** (function) - Required - Async function to execute. It receives the current attempt number and returns a value of type `T`. - **isRetryable** (function) - Required - Function that determines if an error should trigger a retry. It receives the error and the next attempt number. - **options** (object) - Optional - Configuration object for retry behavior. - **baseDelayMs** (number) - Optional - Base delay for exponential backoff (default: 100ms). - **maxDelayMs** (number) - Optional - Maximum delay between retries (default: 3000ms). - **verbose** (boolean) - Optional - Enable logging of retry attempts. ### Retry Delay Calculation The retry delay is calculated using the "Full Jitter" approach: `random_between(0, min(2^attempt * baseDelayMs, maxDelayMs))`. ``` -------------------------------- ### Durable Object Shard Group Names Source: https://github.com/lambrospetrou/durable-utils/blob/main/README.md Demonstrates how to use different Durable Object namespaces or configurations by specifying a `shardGroupName`. This allows for multiple independent groups of shards within the same Durable Object Namespace. ```javascript describe("shardGroupName", async () => { it("default prefix should not conflict with shard group names", async () => { const sdo = new StaticShardedDO(env.SQLDO, { numShards: 3 }); const result = await sdo.one("test", async (stub) => { return await stub.actorId(); }); const sdo2 = new StaticShardedDO(env.SQLDO, { numShards: 3, shardGroupName: "groupOfShards2", }); const result2 = await sdo2.one("test", async (stub) => { return await stub.actorId(); }); const sdo3 = new StaticShardedDO(env.SQLDO, { numShards: 3, shardGroupName: "groupOfShards3", }); const result3 = await sdo3.one("test", async (stub) => { return await stub.actorId(); }); // Even though we use the same partition key, // the actual DOs handling the request are different. expect(result).not.toEqual(result2); expect(result).not.toEqual(result3); expect(result2).not.toEqual(result3); }); }); ``` -------------------------------- ### Execute Function with Conditional Retries Source: https://github.com/lambrospetrou/durable-utils/blob/main/README.md Use `tryWhile` to execute an async function with retry logic based on a condition. This is useful for operations where retries should continue as long as an error is retryable and a maximum attempt count is not exceeded. ```javascript import { tryWhile } from "durable-utils/retries"; import { isErrorRetryable } from "durable-utils/do-utils"; await tryWhile( async (_attempt) => fetch(url), (err, nextAttempt) => nextAttempt < 5 && isErrorRetryable(err) ); ``` -------------------------------- ### Check if Durable Object Error is Retryable Source: https://github.com/lambrospetrou/durable-utils/blob/main/README.md Determines if a Durable Object error should be retried using `isErrorRetryable`. This function follows Cloudflare's official error handling best practices and excludes overloaded errors. ```javascript import { isErrorRetryable } from "durable-utils/do-utils"; if (isErrorRetryable(error)) { // Safe to retry the operation } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.