Queries and OcaltQL
Chapter 2

What Adds Up, and Spending Less

By the end of this chapter you will be able to

Before you start

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 pagesOne 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 SCHEDULEOne query every time the job fires. EVERY 1 MINUTE is 1,440 a day.
WATCHOne per poll, and one more each time the trigger fires.
TUNNEL and SERVEOne to open, then one per visit to the URL produced.
BridgesOne per connection to an audio or video bridge.

2.2 Estimating before you commit

Worked Example 2.1

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 ?job

What it costs.

1 query now (this script)
+ 1 query per run: 60 an hour, 1,440 a day, about 43,200 a month

Line by line.

NEW CRON ... EVERY 1 MINUTECreating the job is part of this script: one query in total.
Each runEvery firing is its own execution, so its own query.
The monthly figure1,440 a day is more than Starter's whole allowance. On Starter this job alone needs Pro or credits.
Worked Example 2.2

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 ?job

What it costs.

24 queries a day, about 720 a month

Line by line.

EVERY 1 HOURSixty 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.

Worked Example 2.3

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.

saved

Line by line.

Two DIRECTIVE commands and a FILE WRITEAll inside one execution.
CostOne 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.

Worked Example 2.4

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 ?result

What comes back.

(the slow response)

Line by line.

SET PROMISE / WAIT FORThe 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.

Worked Example 2.5

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 rebuilt

Line by line.

prices.jsonA 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 DAYRunning this daily costs 30 queries a month, where a dynamic page viewed 1,000 times a day would cost 30,000.

2.6 Practice

Practice 2.6 · one gap

A WATCH polls every 5 minutes and never fires. Queries a day?

____ queries a day
Show the answer

288: 24 hours times 12 polls an hour.

Practice 2.7 · two gaps

Complete the rule for tunnels.

One query to ____ it, and one per _____.
Show the answer

open, visit.

Practice 2.8 · no scaffold

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 MINUTE

If 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