What Adds Up, and Spending Less
By the end of this chapter you will be able to
- identify the things that spend queries without you running anything;
- estimate what a site, a schedule or a watch will cost in a day and a month;
- choose the cheaper of two designs that do the same work;
- apply the habits that keep spending low.
Before you start
- Chapter 1.
The big picture
A query that you send yourself is easy to count. The ones that add up are the ones that run without you: a page every visitor loads, a job that fires every minute, a watch checking something all day. None is expensive alone, but each repeats.
This chapter shows how to see that cost before it happens, and how to design the same work to spend less.
Key terms
- Recurring cost
- Queries spent repeatedly by something that runs on its own.
- Batching
- Doing several pieces of work in one execution, and so one query.
- Interval
- How often a CRON, SCHEDULE or WATCH runs.
- Static file
- A file served as it is, with no OcaltQL run. Static files are free.
2.1 The things that repeat
| Site Mode pages | One query per page view of a .oql file, charged to the site's owner. A page loaded 2,000 times is 2,000 queries. |
| CRON and SCHEDULE | One query every time the job fires. EVERY 1 MINUTE is 1,440 a day. |
| WATCH | One per poll, and one more each time the trigger fires. |
| TUNNEL and SERVE | One to open, then one per visit to the URL produced. |
| Bridges | One per connection to an audio or video bridge. |
2.2 Estimating before you commit
A job that runs every minute
Task. Work out what an every-minute health check costs.
The script.
NEW OPERATION health
OPEN
FETCH "https://example.ocalt.com/status.json" SET ?s
AFTER EMIT ?s
CLOSE
AFTER NEW CRON [RUN health] EVERY 1 MINUTE STARTING NOW SET ?jobWhat it costs.
1 query now (this script)
+ 1 query per run: 60 an hour, 1,440 a day, about 43,200 a monthLine by line.
| NEW CRON ... EVERY 1 MINUTE | Creating the job is part of this script: one query in total. |
| Each run | Every firing is its own execution, so its own query. |
| The monthly figure | 1,440 a day is more than Starter's whole allowance. On Starter this job alone needs Pro or credits. |
The same check, hourly
Task. Change the interval, and see the cost change.
The script.
NEW OPERATION health
OPEN
FETCH "https://example.ocalt.com/status.json" SET ?s
AFTER EMIT ?s
CLOSE
AFTER NEW CRON [RUN health] EVERY 1 HOUR STARTING NOW SET ?jobWhat it costs.
24 queries a day, about 720 a monthLine by line.
| EVERY 1 HOUR | Sixty times fewer runs, so sixty times fewer queries. Choose the slowest interval that still answers the question. |
Think about it
A site's home page runs OcaltQL and gets 800 visits a day. Its images and CSS are loaded 6,000 times a day. How many queries does it spend?
Show the answer
800. Only the .oql page views are queries; the static files are free.
2.3 Batching: one script, one query
The most effective habit is the simplest: do the work in one script. Three scripts that each do one step cost three queries; one script that chains all three costs one.
Three steps, one query
Task. Command two machines and record the result, in a single execution.
The script.
DIRECTIVE "home-server" EXEC "df -h /" SET ?disk
AFTER DIRECTIVE "study-laptop" EXEC "uptime" SET ?up
AFTER FILE WRITE ?disk("stdout") & ?up("stdout") TO "/root/reports/machines.txt"
AFTER EMIT "saved"What comes back.
savedLine by line.
| Two DIRECTIVE commands and a FILE WRITE | All inside one execution. |
| Cost | One query, where three separate requests would have cost three. |
2.4 Waiting without spending
Checking again and again whether something has finished is the other common way to spend queries. Where the work is inside a script, SET PROMISE and WAIT FOR wait for it within the same execution, at no extra cost.
Waiting inside the script
Task. Start a slow request and wait for it, without sending a second script to check on it.
The script.
FETCH "https://example.ocalt.com/slow.php" SET PROMISE ?job
AFTER WAIT FOR ?job SET ?result
AFTER EMIT ?resultWhat comes back.
(the slow response)Line by line.
| SET PROMISE / WAIT FOR | The waiting happens inside the one execution: still one query. |
2.5 Keeping site pages cheap
Every .oql page view is a query, so serve as much as possible as static files. A page whose content changes rarely can be generated once, by a script or a job, and saved as HTML. Visitors then load the saved file for free.
Generating a page once, serving it free
Task. Save the day's price list as a static file, once, rather than querying the database on every visit.
The script.
SELECT ROWS FROM DB "shop" TABLE "products" ORDER BY "name" SET ?rows
AFTER CAST ?rows AS JSON SET ?json
AFTER FILE WRITE ?json TO "/root/sites/shop/prices.json"
AFTER EMIT "prices.json rebuilt"What comes back.
prices.json rebuiltLine by line.
| prices.json | A static file holding every price: loading it costs nothing, however many visitors there are. The page reads it in the browser. |
| One CRON EVERY 1 DAY | Running this daily costs 30 queries a month, where a dynamic page viewed 1,000 times a day would cost 30,000. |
2.6 Practice
A WATCH polls every 5 minutes and never fires. Queries a day?
____ queries a dayShow the answer
288: 24 hours times 12 polls an hour.
Complete the rule for tunnels.
One query to ____ it, and one per _____.Show the answer
open, visit.
A script runs every 10 minutes and each run commands three machines. What does it cost a day?
Show the answer
144 queries: one per run (6 an hour for 24 hours). Commanding the machines is inside each run.
2.7 Common mistakes
Mistake: polling from outside
Sending a new script every few seconds to check on work costs a query each time. Wait inside the script with SET PROMISE and WAIT FOR.
Mistake: the fastest interval by default
NEW CRON [RUN report] EVERY 1 MINUTEIf the answer only matters daily, EVERY 1 DAY costs 1,440 times less.
Mistake: dynamic pages for content that rarely changes
Generate it once as HTML. Static files are free to serve.
Mistake: one script per step
Chain the steps with AFTER. One script is one query, however many steps it takes.
2.8 Check your understanding
1. What spends queries without you sending anything?
Site Mode page views, CRON and SCHEDULE runs, WATCH polls and triggers, TUNNEL and SERVE visits, and bridge connections.
2. Is creating a CRON job a query?
Only as part of the script that creates it. Each run afterwards is a query.
3. How do you wait for slow work without spending?
SET PROMISE and WAIT FOR, inside the same script.
Summary
- Recurring costs come from things that run without you: pages, jobs, watches, tunnels, serves and bridges.
- Estimate before committing: runs per day, times 30 for the month.
- Batch work into one script, wait inside it, and choose the slowest interval that answers the question.
- Serve rarely-changing pages as static files, which are free.