Packages
Run you Gleam programs on Cloudflare's 'World Computer'/Developer Platform
Current section
Files
Jump to
Current section
Files
src/plinth/cloudflare/workflow.gleam
import gleam/dynamic.{type Dynamic}
import gleam/dynamic/decode
import gleam/int
import gleam/javascript/array.{type Array}
import gleam/javascript/promise.{type Promise}
import gleam/json.{type Json}
import gleam/list
import gleam/option.{type Option, None}
import plinth/cloudflare/utils
pub type Entrypoint
pub type InitialEvent(t) {
InitialEvent(payload: t, timestamp: String, instance_id: String)
}
pub fn initial_event_decoder(payload_decoder) {
use payload <- decode.field("payload", payload_decoder)
// TODO date
// use timestamp <- decode.field("timestamp", decode.string)
use instance_id <- decode.field("instance_id", decode.string)
decode.success(InitialEvent(payload, "timestamp", instance_id))
}
pub type SentEvent(t) {
SentEvent(type_: String, payload: t, timestamp: String)
}
pub fn sent_event_decoder(payload_decoder) {
use type_ <- decode.field("type", decode.string)
use payload <- decode.field("payload", payload_decoder)
decode.success(SentEvent(type_, payload, "timestamp"))
}
pub type Step
@external(javascript, "../../plinth_cloudflare_workflow_ffi.mjs", "do_")
fn do_do(
step: Step,
name: String,
config: json.Json,
callback: fn() -> Promise(Json),
) -> Promise(Dynamic)
pub fn do(step, name, config, callback) {
do_do(step, name, config_to_arg(config), callback)
}
pub type StepConfig {
StepConfig(retries: Option(Retries), timeout: Option(Duration))
}
fn config_to_arg(config) {
let StepConfig(retries:, timeout:) = config
utils.sparse([
#("retries", json.nullable(retries, retries_to_arg)),
#("timeout", json.nullable(timeout, duration_to_arg)),
])
}
pub fn default() {
StepConfig(retries: None, timeout: None)
}
pub type Retries {
Retries(
limit: Int,
// initial delay
delay: Duration,
backoff: Backoff,
)
}
fn retries_to_arg(retries) {
let Retries(limit:, delay:, backoff:) = retries
utils.sparse([
#("limit", json.int(limit)),
#("delay", duration_to_arg(delay)),
#("backoff", backoff_to_arg(backoff)),
])
}
pub type Backoff {
Constant
Linear
Exponential
}
fn backoff_to_arg(backoff) {
case backoff {
Constant -> "constant"
Linear -> "linear"
Exponential -> "exponential"
}
|> json.string
}
@external(javascript, "../../plinth_cloudflare_workflow_ffi.mjs", "sleep")
fn do_sleep(step: Step, name: String, duration: json.Json) -> Promise(Nil)
pub fn sleep(step, name, duration) {
do_sleep(step, name, duration_to_arg(duration))
}
@external(javascript, "../../plinth_cloudflare_workflow_ffi.mjs", "sleep_until")
pub fn sleep_until(step: Step, name: String, until: Int) -> Promise(Nil)
@external(javascript, "../../plinth_cloudflare_workflow_ffi.mjs", "wait_for_event")
fn do_wait_for_event(
step: Step,
name: String,
options: json.Json,
) -> Promise(Result(Dynamic, String))
/// returns an error if it timed out
pub fn wait_for_event(
step,
name: String,
type_: String,
timeout: Option(Duration),
) {
let options =
utils.sparse([
#("type", json.string(type_)),
#("timeout", json.nullable(timeout, duration_to_arg)),
])
do_wait_for_event(step, name, options)
}
pub type Workflow
@external(javascript, "../../plinth_cloudflare_workflow_ffi.mjs", "create")
fn do_create(workflow: Workflow, options: json.Json) -> Promise(Instance)
pub fn create(workflow, options) {
do_create(workflow, create_options_to_arg(options))
}
@external(javascript, "../../plinth_cloudflare_workflow_ffi.mjs", "create_batch")
fn do_create_batch(
workflow: Workflow,
options: Array(json.Json),
) -> Promise(Array(Instance))
pub fn create_batch(workflow, options) {
let options = list.map(options, create_options_to_arg)
do_create_batch(workflow, array.from_list(options))
}
pub type CreateOptions {
CreateOptions(id: Option(String), params: json.Json)
}
fn create_options_to_arg(options) {
let CreateOptions(id:, params:) = options
utils.sparse([#("id", json.nullable(id, json.string)), #("params", params)])
}
@external(javascript, "../../plinth_cloudflare_workflow_ffi.mjs", "get")
pub fn get(workflow: Workflow, id: String) -> Promise(Result(Instance, String))
pub type Instance
@external(javascript, "../../plinth_cloudflare_workflow_ffi.mjs", "id")
pub fn id(instance: Instance) -> String
@external(javascript, "../../plinth_cloudflare_workflow_ffi.mjs", "status")
pub fn status(instance: Instance) -> Promise(InstanceStatus)
pub type InstanceStatus {
InstanceStatus(status: String, error: Option(String), output: Dynamic)
}
@external(javascript, "../../plinth_cloudflare_workflow_ffi.mjs", "pause")
pub fn pause(instance: Instance) -> Promise(Nil)
@external(javascript, "../../plinth_cloudflare_workflow_ffi.mjs", "resume")
pub fn resume(instance: Instance) -> Promise(Nil)
@external(javascript, "../../plinth_cloudflare_workflow_ffi.mjs", "restart")
pub fn restart(instance: Instance) -> Promise(Nil)
@external(javascript, "../../plinth_cloudflare_workflow_ffi.mjs", "terminate")
pub fn terminate(instance: Instance) -> Promise(Nil)
@external(javascript, "../../plinth_cloudflare_workflow_ffi.mjs", "send_event")
fn do_send_event(instance: Instance, options: json.Json) -> Promise(Nil)
pub fn send_event(instance, type_, payload) {
do_send_event(
instance,
utils.sparse([#("type", json.string(type_)), #("payload", payload)]),
)
}
pub type Duration {
Milliseconds(Int)
Seconds(Int)
Minutes(Int)
Hours(Int)
Days(Int)
Weeks(Int)
Months(Int)
Years(Int)
}
fn duration_to_arg(duration) {
case duration {
Milliseconds(x) -> json.int(x)
Seconds(x) -> json.string(human(x, "second"))
Minutes(x) -> json.string(human(x, "minute"))
Hours(x) -> json.string(human(x, "hour"))
Days(x) -> json.string(human(x, "day"))
Weeks(x) -> json.string(human(x, "week"))
Months(x) -> json.string(human(x, "month"))
Years(x) -> json.string(human(x, "year"))
}
}
fn human(quantity, unit) {
int.to_string(quantity)
<> " "
<> unit
<> case quantity {
1 -> ""
_ -> "s"
}
}