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:
The default config that the database worker ships with is below, it will work well for our purposes but let’s modify its url to put iii.db in the ./data folder.
The database worker will automatically create 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 owns its schema. Build up the changes to link/src/index.ts in pieces. First add the DB constant near the top of the file:
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

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

Setup database retrieval

Change 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. Pull the write into its own link::record_click function so the redirect records a click instead of issuing SQL itself, and so the next chapter can move that work onto a queue without touching the redirect’s logic. Add it below link::resolve:
src/index.ts
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 and while adding recovery from database failures.
Save the file, create a link, and follow it a few times:
The durable history is now queryable with SQL:

Conclusion

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.