Repository navigation
Lifetimes And Events
The factory reuses a name's pipeline — its handlers and its pooled connections — until the handler
lifetime runs out (two minutes unless set with withHandlerLifetime), then builds the next. A client
made from an expired pipeline keeps working; the expired pipeline is closed after one more lifetime.
Programs hear about this, and about every request, through plain listeners passed to
Factory.buildWith. The package carries the events through a mediator of its own; programs never
build or import one.
module Ex07Lifetimes
import Std.Concurrent as Concurrent
import Std.Http as Http
import Std.Io as Io
import Std.Result as Result
import Std.Sync as Sync
import PuduLangHttpClient.Client as Client
import PuduLangHttpClient.Events as Events
import PuduLangHttpClient.Factory as Factory
import PuduLangHttpClient.Factory.Builder as Builder
import PuduLangHttpClient.Stub as Stub
export fn main() -> Int {
let lines = Sync.cell([])
let lock = Sync.mutex()
let note = fn(line: Str) -> () {
let _noted = Sync.withLock(&lock, fn() -> () { let _kept = Sync.set(&lines, Result.unwrapOr(Sync.get(&lines), []).push(line)) })
}
let listeners = Events.listeners()
.onPipelineChanged(|event: Events.PipelineChanged| note(event.client + " #" + show(event.generation) + " " + show(event.stage)))
.onRequestCompleted(|event: Events.RequestCompleted| note(event.method + " " + event.uri + " " + show(event.status)))
let stub = Stub.create()
Stub.respond(&stub, Http.Get, "/ping", 200, "pong")
let factory = match Factory.buildWith(&Factory.Options{listeners: listeners}, [
Builder.named("pinger").withBaseAddress("https://ping.test/").withPrimary(|| Stub.send(&stub)).withHandlerLifetime(20)
]) {
case Ok(built) => built
case Err(invalid) => panic(Factory.explain(&invalid))
}
let _first = Client.getText(&Factory.createClient(&factory, "pinger"), "ping")
let _rested = Concurrent.sleep(30)
let _second = Client.getText(&Factory.createClient(&factory, "pinger"), "ping")
let _graced = Concurrent.sleep(30)
let _third = Client.getText(&Factory.createClient(&factory, "pinger"), "ping")
Factory.dispose(&factory)
let seen = Result.unwrapOr(Sync.get(&lines), [])
for line in seen { let _said = Io.writeLine(line) }
if seen.contains("pinger #1 Closed") && seen.contains("pinger #3 Created") && seen.contains("GET https://ping.test/ping 200") { 0 } else { 1 }
}
Check it and run it:
pudu check src/Ex07Lifetimes.pudu
pudu run src/Ex07Lifetimes.puduOutput:
pinger #1 Created
GET https://ping.test/ping 200
pinger #2 Created
pinger #1 Expired
GET https://ping.test/ping 200
pinger #3 Created
pinger #2 Expired
pinger #1 Closed
GET https://ping.test/ping 200
pinger #3 Closed
pinger #2 Closed
Events.listeners() with onRequestStarted, onRequestCompleted, onRequestFailed, and
onPipelineChanged adds listeners; every event derives Json.Encode, so a listener can forward it
as JSON. With withHandlerLifetime(Defaults.INFINITE) a pipeline is never renewed — pair it with
withPooledConnectionLifetime so connections are.
- Previous: The Transport
- Next: Resilience
- Reference Index