CRUD Application
Production-ready Node.js API with automated testing, backups, and Slack notifications.
Features demonstrated
- Zero-downtime rolling deployments
- Scheduled database backups
- Automated testing via cron
- Slack webhook notifications
- Environment variable management
Configuration
version: "1"
env:
file: ".env.example"
services:
node__web_server:
command: "node server.js"
deployment_strategy: "rolling_start"
env:
vars:
NODE_ENV: "${NODE_ENV}"
PORT: "${PORT}"
DATABASE_URL: "${DATABASE_URL}"
restart_policy: "on_failure"
retries: "10"
backoff: "10s"
webhooks:
on_success:
url: "${SLACK_WEBHOOK_SUCCESS_URL}"
method: "POST"
timeout: "30s"
on_failure:
url: "${SLACK_WEBHOOK_FAILURE_URL}"
method: "POST"
timeout: "30s"
cron:
automated_testing:
command: "npm test"
schedule: "0 */6 * * *"
retries: "3"
timeout: "120s"
webhooks:
on_failure:
url: "${SLACK_WEBHOOK_TEST_FAILURE_URL}"
method: "POST"
database_backup:
command: >
pg_dump ${DATABASE_URL} >
/backups/db_$(date +%Y%m%d_%H%M%S).sql
schedule: "0 2 * * *"
retries: "5"
timeout: "300s"
webhooks:
on_success:
url: "${SLACK_WEBHOOK_BACKUP_URL}"
method: "POST"
on_failure:
url: "${SLACK_WEBHOOK_BACKUP_FAILURE_URL}"
method: "POST"
Environment file
Create .env.example:
NODE_ENV=production
PORT=3000
DATABASE_URL=postgres://user:pass@localhost/crud_db
SLACK_WEBHOOK_SUCCESS_URL=https://hooks.slack.com/services/xxx
SLACK_WEBHOOK_FAILURE_URL=https://hooks.slack.com/services/yyy
SLACK_WEBHOOK_TEST_FAILURE_URL=https://hooks.slack.com/services/zzz
SLACK_WEBHOOK_BACKUP_URL=https://hooks.slack.com/services/aaa
SLACK_WEBHOOK_BACKUP_FAILURE_URL=https://hooks.slack.com/services/bbb
Application code
server.js
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;
app.use(express.json());
// In-memory database for demo
let items = [];
let nextId = 1;
app.get('/items', (req, res) => {
res.json(items);
});
app.post('/items', (req, res) => {
const item = { id: nextId++, ...req.body };
items.push(item);
res.status(201).json(item);
});
app.put('/items/:id', (req, res) => {
const id = parseInt(req.params.id);
const index = items.findIndex(item => item.id === id);
if (index === -1) return res.status(404).json({ error: 'Not found' });
items[index] = { id, ...req.body };
res.json(items[index]);
});
app.delete('/items/:id', (req, res) => {
const id = parseInt(req.params.id);
items = items.filter(item => item.id !== id);
res.status(204).send();
});
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
Run it
$ cd examples/crud
$ npm install
$ sysg start --config crud.sysg.yaml
Operations
Deploy new version
# Update code
$ git pull
$ npm install
# Rolling restart - zero downtime
$ sysg restart node__web_server
View logs
$ sysg logs --service node__web_server
Manual backup
$ sysg cron trigger database_backup
Check cron schedules
$ sysg cron list
What happens
- Web server starts and serves API on configured port
- Tests run automatically every 6 hours
- Backups execute nightly at 2 AM
- Slack notifications fire on:
- Successful/failed deployments
- Failed tests
- Backup completion or failure
- Rolling deployments ensure zero downtime during updates
Monitoring
$ sysg status # Service health
$ sysg cron status # Cron job history
$ sysg logs --service automated_testing # Test results
$ sysg logs --service database_backup # Backup logs
See also
- Configuration - Service definitions
- Cron - Scheduled tasks
- Webhooks - Notifications
- Rolling deployments