Skip to main content
Linkly’s links live in iii-state, which you set to in-memory back in Chapter 1. Restart the engine and everything is gone. In this chapter you add a database worker (SQLite) that holds the durable record of links and a timestamped row for every click on a short code. iii-state stays in the picture as a fast read cache in front of the database.
iii-state can also persist on its own (store_method: file_based with a file_path). This chapter uses a dedicated database worker instead, which gives you durable storage plus SQL to query it.

Add the database worker

State is a fast cache, but you also want a durable record you can run SQL over: every link, and a timestamped row each time someone follows one. Add the database worker:
Adjust your database worker in config.yaml so that it looks like the below.
The database worker will automatically create ./data/iii.db on first run.
The database worker supports more than SQLite, refer to the database worker docs for all supported databases.
config.yaml
The worker will be in charge of defining its own schema. We’ll build up the necessary changes to link/src/index.ts in pieces.

Define the database

First add the DB constant near the top of link/src/index.ts:
src/index.ts
Now we’re going to adapt the existing link::create and link::resolve functions so that they write and read from our new database while using our state worker as a hot cache.

Create a schema

Add an ensureSchema() function at the end of link/src/index.ts that creates both tables on startup. The database worker accepts SQL through its database::execute function:
src/index.ts

Setup database writing

Modify link::create to write to both the database (durable record) and iii-state (hot cache):
src/index.ts

Setup database retrieval

Modify link::resolve to check the cache first; on a miss, fall back to the database and warm the cache for the next read. It’s easiest to replace the existing link::resolve function with our new version:
src/index.ts

Add click tracking

Since we have a database now, you can start click tracking. Make a new function (link::record_click) to do that and save it to the database. The next chapter will move this work onto a queue so that it can run without touching the redirect’s logic. Add it below link::resolve:
src/index.ts

Update http::redirect to call link::record_click

Now update http::redirect to trigger it directly, right before returning the redirect:
src/index.ts
The database write for clicks adds latency to every redirect. The next chapter moves it onto a durable queue that removes the latency while also adding recovery from database failures.

Try the click tracking

Now let’s see the click tracking in action. Save the file, create a link, and simulate clicking it a few times:
The durable history is now queryable with SQL:

Conclusion

Did you know that --help works with function id’s as well? Try running: iii trigger database::query --help to see what arguments database::query accepts.
Linkly’s links are now durable: the database is the source of truth, iii-state keeps lookups fast, and every redirect appends a timestamped row to the clicks table. But that row is written on the redirect’s hot path, so a slow database write slows the redirect. Next, in Ch. 4: Make it durable, you move that write onto a queue so redirects stay fast.