Examples
Services
About
An app of two services: the shop, and the billing it calls.
quillo run services/app.qwe one process
quillo run services/app.qwe --split a process for each service
Either way, open http://localhost:8080. The code does not change: in one process, the shop calls billing directly; split, over HTTP, signed with QUILLO_SERVICE_SECRET (--split makes one). To run billing on a machine of its own, start it alone and tell the others where it is:
QUILLO_SERVICE_SECRET=... quillo run billing.qwe --port 8081 --base /billing --as-service QUILLO_SERVICE_SECRET=... quillo run app.qwe --service-url billing=http://10.0.0.5:8081
Run it
$ quillo run services/app.qwe --watchservices/app.qwe
services/app.qwe
service /shop = "shop.qwe"service /billing = "billing.qwe"route GET / = <html> <head><title>Services</title></head> <body> <h1>Two services</h1> <p><a href="/shop">The shop</a> sells mugs; <a href="/billing">billing</a> keeps the invoices.</p> <p>Billed so far: {billing.total() ?? "billing is not answering"} cents.</p> </body></html>services/shop.qwe
services/shop.qwe
// The shop: a page to buy from, which bills through the billing service.// `billing.invoice(...)` reads as a call of a function; where billing runs// (this process, or a server of its own) is not the shop's concern. When// it runs elsewhere, a call may take two seconds, and is tried once more if// it did not get through.service billing = "billing.qwe" { timeout: "2s", retries: 1 }let PRICE = 1200route GET / = <html> <head><title>Shop</title></head> <body> <h1>A mug, {PRICE} cents</h1> <form method="post" action="/buy"> <input name="name" placeholder="Your name"/> <button>Buy</button> </form> </body></html>route POST /buy { let inv = billing.invoice(request.form.name ?? "", PRICE, "a mug") if is_err(inv) { reply 400 <p>Not bought: {inv.error}</p> } let mine = billing.invoices_of(inv.customer) ?? [] <html><body> <h1>Thank you, {inv.customer}</h1> <p>Invoice #{inv.id}: {inv.cents} cents. You have {len(mine)} with us.</p> <p><a href="/">Buy another</a></p> </body></html>}services/billing.qwe
services/billing.qwe
// Billing: invoices, as a service of its own. Other programs call its// `server fn`s (`billing.invoice(...)`); its page lists what it billed.// See app.qwe for running it in one process or as a server of its own.let invoices = []server fn invoice(customer: str, cents: int, note: str = "") -> map ! str { if trim(customer) == "" { return err("An invoice is for someone") } if cents <= 0 { return err("An invoice is for something") } let inv = { id: len(invoices) + 1, customer: trim(customer), cents, note } invoices = invoices + [inv] inv}server fn invoices_of(customer: str) -> list = invoices | filter((i) => i.customer == customer)server fn total() -> int = invoices | reduce(0, (sum, i) => sum + i.cents)route GET / = <html> <head><title>Billing</title></head> <body> <h1>Billing</h1> <p>{len(invoices)} invoices, {total()} cents in all.</p> <ul>{for i in invoices => <li>#{i.id} · {i.customer} · {i.cents} cents {i.note}</li>}</ul> </body></html>Thread
Thread 0 posts
On Services: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.