Cheat notes · Module 02 · The backend plugin
Database, config and a schedule
A five-minute review for when you have done this module and want it back in your head. Open the full module for the steps and the lab, or the full text to print.
The idea
A stored score with a time on it is something teams can trust. Every plugin that stores data or runs jobs uses the same three services: its own database with Knex migrations, a config schema, and a scheduler that runs a job once across replicas.
Remember
- Database service: each plugin gets its own database (
backstage_plugin_<id>) and a Knex client. Ship migrations in the package (migrations/, run once each in name order) and listmigrationsinfiles. - Config schema: a
config.d.tsnamed inpackage.jsonunderconfigSchemadocuments your keys;config:checkand the backend validate against it. - Scheduler:
scheduler.scheduleTask({ id, frequency, timeout, initialDelay, fn }). With several replicas, a database lock makes only one run it. - Acting as the plugin: a scheduled job has no user.
auth.getOwnServiceCredentials()gives the plugin its own credentials to call the catalog. - Read config with
config.getOptionalStringArray(...), and schedules withreadSchedulerServiceTaskScheduleDefinitionFromConfig.
Pitfalls
- A string where a list belongs (
disabledChecks: has-runbook): the plugin fails at startup withgot string, wanted string-arrayand the API answers503.config:check --strictin CI catches it, but only for keys you described inconfig.d.ts. - No
config.d.ts: typos in config are silently ignored and nobody knows which keys exist.
Commands
yarn backstage-cli config:check --strict | Validate config against every schema |
curl -s -H "Authorization: Bearer $PORTAL_API_TOKEN" localhost:7007/api/readiness/scorecards | Stored scorecards |
docker exec portal-db psql -U postgres -d backstage_plugin_readiness -c 'select entity_ref, score from readiness_scorecards' | The rows in the plugin's own database |
Config and its schema
# app-config.yaml
readiness:
schedule:
frequency: { minutes: 30 }
timeout: { minutes: 5 }
initialDelay: { seconds: 15 }
disabledChecks: []
// config.d.ts
export interface Config {
readiness?: {
schedule?: SchedulerServiceTaskScheduleDefinitionConfig;
disabledChecks?: string[];
};
}
Test yourself
Answer in your head first, then open the answer.
Why does the readiness backend get its own database?
Each plugin owns its tables and migrations, so plugins cannot break each other's data.
Two replicas run the same scheduled task. How often does it run?
Once per interval: a lock in the database picks one replica.
Whose credentials does the scheduled job use to read the catalog?
The plugin's own service credentials.
Where module 02 leaves you: Every 30 minutes the backend scores every component and stores the result in backstage_plugin_readiness. Settings live under readiness: in app-config.yaml. Merged.