Startup Checks
Call DripDrop.startup_check/0 during host boot. The check validates channel
configuration, optional provider dependencies, encryption key decoding,
scheduler callbacks, unsubscribe URL builder requirements, and PgFlow job
registration when DripDrop.Schedulers.Pgflow is configured.
When PgFlow is the scheduler, every module listed in
config :dripdrop, :pgflow, jobs: ... must have its PgFlow job migration
generated and migrated. The default setup uses DripDrop.Jobs.DispatchStep and
DripDrop.Jobs.CronTick.
Schema Checks
Run:
mix dripdrop.check_schema
Use this in CI and deploy smoke checks.
Integration Tests
Integration tests exercise the real PgFlow scheduler, worker polling, webhook
ingest, and database state transitions. Provider HTTP calls stay local through
Req.Test; tests must not call real provider networks.
Run them locally after the test database is up:
docker compose up -d
mix test --only integration
Add new integration tests with DripDrop.IntegrationCase and
@moduletag :integration. Use DripDrop.TestSupport.PgflowHarness when a test
needs a PgFlow worker, and prefer eventually/2 over fixed sleeps for state
that changes in worker processes.
When debugging PgFlow timing flakes:
- Lower
min_poll_interval/max_poll_intervalinPgflowHarness.child_spec/1. - Increase the relevant
eventually/2timeout before adding sleeps. - Inspect
pgflow.step_tasks,pgflow.runs, andpgmq.q_dispatch_stepto see whether work is queued, started, failed, or invisible due to retry delay. - Keep provider stubs in
Req.Testshared mode when the request is made from a PgFlow worker process.
Telemetry
Attach handlers to DripDrop.Telemetry.events/0 for dispatch, policy,
provider ingest, template, hook, short-link, and channel events.
:telemetry.attach_many(
"dripdrop-ops",
DripDrop.Telemetry.events(),
&MyApp.Telemetry.handle_event/4,
nil
)Provider Events
DripDrop.Web.WebhookPlug verifies provider signatures before normalization.
Duplicate provider events skip duplicate persistence and emit telemetry.
Duplicate replies can still run configured reply handling.
Deleting a Tenant
When a host deletes an account, remove its DripDrop data with:
{:ok, deleted_counts} = DripDrop.delete_tenant(tenant_key)It deletes every row whose tenant_key matches, across all DripDrop tables,
in one transaction, and returns the deleted count per table. Global rows
(tenant_key: nil) and other tenants' rows are never selected. A nil or
blank key raises ArgumentError.
If a row outside the tenant references one of the tenant's rows, the delete
would cascade into or null out that row, so nothing is deleted and the call
returns {:error, {:cross_tenant_references, references}}, listing each
%{table:, column:, count:}.
Uninstall
Generate the uninstall SQL:
mix dripdrop.uninstall
The task prints the destructive SQL for an operator to review; it does not drop the schema automatically.