Feature: io.random() (#716)
* Add io.random * Add changeset --------- Co-authored-by: Eric Allam <eric@trigger.dev>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
---
|
||||
|
||||
Add `io.random()` which wraps `Math.random()` in a Task with helpful options.
|
||||
@@ -0,0 +1,21 @@
|
||||
```typescript Random example
|
||||
client.defineJob({
|
||||
id: "random-job",
|
||||
name: "Random Job",
|
||||
version: "0.0.1",
|
||||
trigger: eventTrigger({
|
||||
name: "example.event",
|
||||
}),
|
||||
run: async (payload, io, ctx) => {
|
||||
// generate random numbers
|
||||
const small = await io.random("random-small");
|
||||
const large = await io.random("random-large", {
|
||||
min: 10,
|
||||
max: 200,
|
||||
round: true
|
||||
});
|
||||
|
||||
await io.logger.info(`${small} is smaller than ${large}`);
|
||||
},
|
||||
});
|
||||
```
|
||||
@@ -335,6 +335,7 @@
|
||||
"sdk/io/logger",
|
||||
"sdk/io/sendevent",
|
||||
"sdk/io/backgroundfetch",
|
||||
"sdk/io/random",
|
||||
"sdk/io/try",
|
||||
"sdk/io/registerinterval",
|
||||
"sdk/io/unregisterinterval",
|
||||
|
||||
@@ -40,6 +40,10 @@ If you want to send an event from outside a run (e.g. just from your backend) yo
|
||||
|
||||
`io.backgroundFetch()` allows you to fetch data from a URL that can take longer that the serverless timeout. The actual `fetch` request is performed on the Trigger.dev platform, and the response is sent back to you. An example use case is fetching data from a slow API, like some AI endpoints.
|
||||
|
||||
### [random()](/sdk/io/random)
|
||||
|
||||
`io.random()` is identical to `Math.random()` when called without options but ensures your random numbers are not regenerated on resume or retry. It will return a pseudo-random floating-point number between optional `min` (default: 0, inclusive) and `max` (default: 1, exclusive). Can optionally `round` to the nearest integer.
|
||||
|
||||
### [try()](/sdk/io/try)
|
||||
|
||||
`io.try()` allows you to run Tasks and catch any errors that are thrown, it's similar to a normal `try/catch` block but works with [io.runTask()](/sdk/io/runtask).
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
---
|
||||
title: "io.random()"
|
||||
sidebarTitle: "random()"
|
||||
description: "`io.random()` is identical to `Math.random()` when called without options but ensures your random numbers are not regenerated on resume or retry. It will return a pseudo-random floating-point number between optional `min` (default: 0, inclusive) and `max` (default: 1, exclusive). Can optionally `round` to the nearest integer."
|
||||
---
|
||||
|
||||
## Parameters
|
||||
|
||||
<Snippet file="stable-key-param.mdx" />
|
||||
<ResponseField name="min" type="number" default="0" required>
|
||||
Sets the lower bound (inclusive). Can't be higher than `max`.
|
||||
</ResponseField>
|
||||
<ResponseField name="max" type="number" default="1" required>
|
||||
Sets the upper bound (exclusive). Can't be lower than `min`.
|
||||
</ResponseField>
|
||||
<ResponseField name="round" type="boolean" default="false" required>
|
||||
Controls rounding to the nearest integer. Any `max` integer will become inclusive when enabled. Rounding with floating-point bounds may cause unexpected skew and boundary inclusivity.
|
||||
</ResponseField>
|
||||
|
||||
## Returns
|
||||
|
||||
A `Promise` that resolves with a pseudo-random number. Always resolves to an integer when rounding is enabled.
|
||||
|
||||
<RequestExample>
|
||||
<Snippet file="random-example.mdx" />
|
||||
</RequestExample>
|
||||
@@ -232,6 +232,90 @@ export class IO {
|
||||
});
|
||||
}
|
||||
|
||||
/** `io.random()` is identical to `Math.random()` when called without options but ensures your random numbers are not regenerated on resume or retry. It will return a pseudo-random floating-point number between optional `min` (default: 0, inclusive) and `max` (default: 1, exclusive). Can optionally `round` to the nearest integer.
|
||||
* @param cacheKey Should be a stable and unique key inside the `run()`. See [resumability](https://trigger.dev/docs/documentation/concepts/resumability) for more information.
|
||||
* @param min Sets the lower bound (inclusive). Can't be higher than `max`.
|
||||
* @param max Sets the upper bound (exclusive). Can't be lower than `min`.
|
||||
* @param round Controls rounding to the nearest integer. Any `max` integer will become inclusive when enabled. Rounding with floating-point bounds may cause unexpected skew and boundary inclusivity.
|
||||
*/
|
||||
async random(
|
||||
cacheKey: string | any[],
|
||||
{
|
||||
min = 0,
|
||||
max = 1,
|
||||
round = false,
|
||||
}: {
|
||||
min?: number;
|
||||
max?: number;
|
||||
round?: boolean;
|
||||
} = {}
|
||||
) {
|
||||
return await this.runTask(
|
||||
cacheKey,
|
||||
async (task) => {
|
||||
if (min > max) {
|
||||
throw new Error(
|
||||
`Lower bound can't be higher than upper bound - min: ${min}, max: ${max}`
|
||||
);
|
||||
}
|
||||
|
||||
if (min === max) {
|
||||
await this.logger.warn(
|
||||
`Lower and upper bounds are identical. The return value is not random and will always be: ${min}`
|
||||
);
|
||||
}
|
||||
|
||||
const withinBounds = (max - min) * Math.random() + min;
|
||||
|
||||
if (!round) {
|
||||
return withinBounds;
|
||||
}
|
||||
|
||||
if (!Number.isInteger(min) || !Number.isInteger(max)) {
|
||||
await this.logger.warn(
|
||||
"Rounding enabled with floating-point bounds. This may cause unexpected skew and boundary inclusivity."
|
||||
);
|
||||
}
|
||||
|
||||
const rounded = Math.round(withinBounds);
|
||||
|
||||
return rounded;
|
||||
},
|
||||
{
|
||||
name: "random",
|
||||
icon: "dice-5-filled",
|
||||
params: { min, max, round },
|
||||
properties: [
|
||||
...(min === 0
|
||||
? []
|
||||
: [
|
||||
{
|
||||
label: "min",
|
||||
text: String(min),
|
||||
},
|
||||
]),
|
||||
...(max === 1
|
||||
? []
|
||||
: [
|
||||
{
|
||||
label: "max",
|
||||
text: String(max),
|
||||
},
|
||||
]),
|
||||
...(round === false
|
||||
? []
|
||||
: [
|
||||
{
|
||||
label: "round",
|
||||
text: String(round),
|
||||
},
|
||||
]),
|
||||
],
|
||||
style: { style: "minimal" },
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/** `io.wait()` waits for the specified amount of time before continuing the Job. Delays work even if you're on a serverless platform with timeouts, or if your server goes down. They utilize [resumability](https://trigger.dev/docs/documentation/concepts/resumability) to ensure that the Run can be resumed after the delay.
|
||||
* @param cacheKey Should be a stable and unique key inside the `run()`. See [resumability](https://trigger.dev/docs/documentation/concepts/resumability) for more information.
|
||||
* @param seconds The number of seconds to wait. This can be very long, serverless timeouts are not an issue.
|
||||
@@ -975,7 +1059,7 @@ export class IO {
|
||||
*/
|
||||
brb = this.yield.bind(this);
|
||||
|
||||
/** `io.try()` allows you to run Tasks and catch any errors that are thrown, it's similar to a normal `try/catch` block but works with [io.runTask()](/sdk/io/runtask).
|
||||
/** `io.try()` allows you to run Tasks and catch any errors that are thrown, it's similar to a normal `try/catch` block but works with [io.runTask()](https://trigger.dev/docs/sdk/io/runtask).
|
||||
* A regular `try/catch` block on its own won't work as expected with Tasks. Internally `runTask()` throws some special errors to control flow execution. This is necessary to deal with resumability, serverless timeouts, and retrying Tasks.
|
||||
* @param tryCallback The code you wish to run
|
||||
* @param catchCallback Thhis will be called if the Task fails. The callback receives the error
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
"misconfigured": "nodemon --watch src/misconfigured.ts -r tsconfig-paths/register -r dotenv/config src/misconfigured.ts",
|
||||
"auto-yield": "nodemon --watch src/auto-yield.ts -r tsconfig-paths/register -r dotenv/config src/auto-yield.ts",
|
||||
"cli-example": "nodemon --watch src/cli-example.ts -r tsconfig-paths/register -r dotenv/config src/cli-example.ts",
|
||||
"random": "nodemon --watch src/random.ts -r tsconfig-paths/register -r dotenv/config src/random.ts",
|
||||
"invoke": "nodemon --watch src/invoke.ts -r tsconfig-paths/register -r dotenv/config src/invoke.ts",
|
||||
"dev:trigger": "trigger-cli dev --port 8080"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import { createExpressServer } from "@trigger.dev/express";
|
||||
import { TriggerClient, eventTrigger } from "@trigger.dev/sdk";
|
||||
|
||||
export const client = new TriggerClient({
|
||||
id: "job-catalog",
|
||||
apiKey: process.env["TRIGGER_API_KEY"],
|
||||
apiUrl: process.env["TRIGGER_API_URL"],
|
||||
verbose: false,
|
||||
ioLogLocalEnabled: true,
|
||||
});
|
||||
|
||||
client.defineJob({
|
||||
id: "random-example",
|
||||
name: "Random Example",
|
||||
version: "1.0.0",
|
||||
enabled: true,
|
||||
trigger: eventTrigger({
|
||||
name: "random.example",
|
||||
}),
|
||||
run: async (payload, io, ctx) => {
|
||||
// just like Math.random() but wrapped in a Task
|
||||
await io.random("random-native");
|
||||
|
||||
// set lower and upper bounds - defaults to 0, 1 respectively
|
||||
await io.random("random-min-max", { min: 10, max: 20 });
|
||||
|
||||
// set lower bound only (inclusive)
|
||||
await io.random("random-min", { min: 0.5 });
|
||||
|
||||
// set upper bound only (exclusive)
|
||||
await io.random("random-max", { max: 100 });
|
||||
|
||||
// round to the nearest integer
|
||||
await io.random("random-round", { min: 100, max: 1000, round: true });
|
||||
|
||||
// rounding with floating-point bounds results in a warning
|
||||
// this example will unexpectedly (but correctly!) output 1 or 2, skewing towards 2
|
||||
await io.random("random-round-float", { min: 0.9, max: 2.5, round: true });
|
||||
|
||||
// negative values work just fine
|
||||
await io.random("random-negative", { min: -100, max: -50 });
|
||||
|
||||
// identical lower and upper bounds result in a warning
|
||||
await io.random("random-warn-bounds", { min: 10, max: 10 });
|
||||
|
||||
// invalid ranges will fail
|
||||
await io.random("random-error", { min: 10, max: 5 });
|
||||
},
|
||||
});
|
||||
|
||||
createExpressServer(client);
|
||||
Reference in New Issue
Block a user