1. Rowfire
  2. Blog

The events your app can't emit

Your application emits events when its code runs. It can't announce what didn't happen. Here is how a SQL trigger catches absences and derived conditions.

  • PostgreSQL
  • Slack
  • Zendesk
  • Braze
  • concepts
  • sql

Most product analytics and messaging tools start from the same assumption: the application tells them what happened. A user signs up, the code calls track("signed_up"), and everything downstream reacts.

That works for events that are a line of code. It fails for three kinds of event that teams ask for all the time.

1. Absences

A trial ends in three days and the account never activated. An urgent ticket has had no first response. A customer hasn’t logged in for 14 days.

Nothing happens at the moment these become true. No request comes in and no handler runs, so there is nowhere to put the tracking call. The usual workaround is a cron job someone has to write, deploy and own.

As a query it is just a WHERE clause:

SELECT a.id AS account_id, a.name AS account, a.owner_email,
       a.trial_ends_at - interval '3 days' AS nudge_at
FROM accounts a
JOIN plans p ON p.id = a.plan_id
WHERE p.name = 'Trial'
  AND a.activated_at IS NULL

The clock doesn’t even have to be a column: here it is three days before the trial ends, computed in the query.

2. Derived conditions

The third declined charge this month. An account past 80% of its seats. Each one is a count, a threshold or a join across tables. Application code could compute them, but only if someone adds that computation to every code path that changes the underlying rows.

The database already holds the answer. A query asks it.

3. Data that is already there

Even when an event could be emitted by the app, adding it means a ticket, a code change and a release. Then it only fires for activity after the release. If the data is in the database today, a trigger on it works today, and a backtest shows what it would have done over the last 120 days before anything is sent.

One query, many subscribers

In Rowfire the query is a trigger: written once by whoever knows the schema. Teams subscribe to it with rules that decide how often one key may fire (once ever, once per day or week, every nth time) and what happens: a Slack message, a Zendesk ticket, a Braze event or a call to any API.

In the live demo, one payment_failed trigger feeds two rules: a #billing heads-up at most once a day per account, and a Zendesk ticket at most once a week. Over 120 days of sample data, 211 declined charges become 105 tickets. The other 106 were retries that would have been duplicates.

See it on the use case page, or try it in the demo.

Questions

Why not add a tracking call to the application?

For an event that a line of code produces, you can. For an absence (a trial that never activated) or a derived condition (the third declined charge this month), no line of code runs at the moment it becomes true, so there is nothing to put the call in.

How quickly does Rowfire notice?

Triggers are polled, within a minute by default. That suits tickets, campaigns and follow-ups, not messages that must arrive instantly, like one-time passcodes.