Pudu programming language
Menu
Package

@chrismichaelps / pudu-lang-httpclient

Named HTTP clients for Pudu: a client factory, delegating handlers, pooled keep-alive connections, handler lifetimes, logging, and resilience

0.1.1Apache-2.01

InstallClose

Resilience.pudu

Pudu58 lines2.5 KB

GitHub ↗
1/** @Examples.Resilience.Program — the standard resilience pipeline against a flaky server */2module Resilience34import Std.Concurrent as Concurrent5import Std.Http as Http6import Std.Http.Server.Reply as Reply7import Std.Http.Server.Route as Route8import Std.Http.Server as Server9import Std.Io as Io10import Std.Result as Result11import Std.Sync as Sync12import PuduLangHttpClient.Client as Client13import PuduLangHttpClient.Factory.Builder as Builder14import PuduLangHttpClient.Factory as Factory15import PuduLangHttpClient.Handlers.Resilience as Resilience16import PuduLangHttpClient as HttpClient17import PuduLangResilience.Retry as Retry1819/// Starts a local server that is busy for the first two requests and answers its address.20fn serve(seen: &Sync.Counter) -> (Server.Running, Str) {21  let counter = *seen22  let running = match Server.start("127.0.0.1", 0) {23    case Ok(found) => found24    case Err(problem) => panic(show(problem))25  }26  let server = Server.server(&Route.routing(&[Route.get("/stock", fn(_request: Route.Request) -> Http.Response {27            let attempt = Result.unwrapOr(Sync.increment(&counter, 1), 0)28            if attempt <= 2 { Http.Response{..Reply.text(503, "busy"), headers: [("retry-after", "0")]} } else { Reply.text(200, "12 in stock") }29          })]))30  let _serving = Concurrent.start(fn() -> () { let _ran = Server.run(&server, &running, 0) })31  (running, "http://127.0.0.1:" + show(Server.portOf(&running)) + "/")32}3334/// Reads stock through the standard pipeline, retrying the busy answers, and answers 0 on success.35fn main() -> Int {36  let seen = Sync.counter(0)37  let (running, base) = serve(&seen)38  let options = Resilience.standardOptions()39  let quick = Resilience.Standard{..options, retry: Retry.Options{..options.retry, delay: 10}}40  let pipeline = match Resilience.standardWith(&quick) {41    case Ok(built) => built42    case Err(_) => panic("the standard pipeline did not build")43  }44  let factory = match Factory.build([Builder.named("inventory").withBaseAddress(base).withHandler(Resilience.handler(pipeline))]) {45    case Ok(built) => built46    case Err(invalid) => panic(Factory.explain(&invalid))47  }48  let stock = Client.getText(&Factory.createClient(&factory, "inventory"), "stock")49  let attempts = Result.unwrapOr(Sync.count(&seen), 0)50  let _said = Io.writeLine(match stock {51      case Ok(text) => text + " after " + show(attempts) + " attempts"52      case Err(failure) => HttpClient.describe(&failure)53    })54  Factory.dispose(&factory)55  let _stopped = Server.stop(&running)56  if stock == Ok("12 in stock") && attempts == 3 { 0 } else { 1 }57}58