The Scheduler Webhook plugin provides HTTP endpoints for Grav's Modern Scheduler, enabling webhook triggers and health monitoring for cloud environments, CI/CD pipelines, and external monitoring systems.
- 🔗 Webhook Triggers - Trigger scheduler via HTTP POST requests
- 💚 Health Monitoring - Check scheduler status via HTTP GET requests
- 🔒 Token Authentication - Secure webhook access with bearer tokens
- 🌐 CORS Support - Optional cross-origin request support
- ☁️ Cloud Ready - Perfect for serverless and containerized deployments
bin/gpm install scheduler-webhook
- Download the plugin from GitHub
- Extract to
/user/plugins/scheduler-webhook
- Run
bin/grav install
to install dependencies
- Grav v1.7.0 or higher
- Modern Scheduler enabled in Grav configuration
- PHP 7.3.6 or higher
First, enable the Modern Scheduler in your Grav configuration:
Admin Panel:
- Navigate to Configuration → Scheduler
- Click on "Modern Features" tab
- Toggle "Enable Modern Scheduler" to ON
- Save configuration
Manual Configuration:
Edit user/config/scheduler.yaml
:
modern:
enabled: true
webhook:
enabled: true
token: 'your-secure-token-here' # Generate with: openssl rand -hex 32
health:
enabled: true
The plugin is enabled by default once installed. You can configure it via:
Admin Panel: Configuration → Plugins → Scheduler Webhook
Manual Configuration:
Edit user/config/plugins/scheduler-webhook.yaml
:
enabled: true
cors: false # Set to true if you need cross-origin requests
URL: /scheduler/webhook
Method: POST
Authentication: Bearer token (optional but recommended)
curl -X POST https://your-site.com/scheduler/webhook \
-H "Authorization: Bearer your-secure-token-here"
Response:
{
"success": true,
"message": "Scheduler executed",
"jobs_run": 3,
"timestamp": "2025-01-24T10:30:00+00:00"
}
When you specify a job ID, the webhook will force-run that job immediately, regardless of its schedule. This is useful for manual triggers or CI/CD pipelines.
curl -X POST https://your-site.com/scheduler/webhook?job=backup \
-H "Authorization: Bearer your-secure-token-here"
Response:
{
"success": true,
"message": "Job force-executed successfully",
"job_id": "backup",
"forced": true,
"output": "Backup completed successfully"
}
Note: This is a manual override - the job runs immediately even if it's not scheduled to run at this time.
URL: /scheduler/health
Method: GET
Authentication: None required (configurable)
curl https://your-site.com/scheduler/health
Response:
{
"status": "healthy",
"last_run": "2025-01-24T10:30:00+00:00",
"last_run_age": 120,
"queue_size": 0,
"failed_jobs_24h": 0,
"scheduled_jobs": 3,
"modern_features": true,
"webhook_enabled": true,
"health_check_enabled": true,
"timestamp": "2025-01-24T10:32:00+00:00"
}
Status values:
healthy
- Last run within 10 minuteswarning
- Last run within 1 hourcritical
- Last run over 1 hour agounknown
- No run history found
.github/workflows/scheduler.yml
:
name: Trigger Grav Scheduler
on:
schedule:
- cron: '*/5 * * * *' # Every 5 minutes
workflow_dispatch: # Manual trigger
jobs:
trigger:
runs-on: ubuntu-latest
steps:
- name: Trigger Scheduler
run: |
curl -X POST ${{ secrets.SITE_URL }}/scheduler/webhook \
-H "Authorization: Bearer ${{ secrets.SCHEDULER_TOKEN }}" \
-f # Fail on HTTP errors
- name: Check Health
run: |
curl ${{ secrets.SITE_URL }}/scheduler/health \
-f # Fail on HTTP errors
.gitlab-ci.yml
:
trigger-scheduler:
stage: deploy
script:
- |
curl -X POST ${SITE_URL}/scheduler/webhook \
-H "Authorization: Bearer ${SCHEDULER_TOKEN}" \
--fail
only:
- schedules
import json
import urllib3
def lambda_handler(event, context):
http = urllib3.PoolManager()
response = http.request(
'POST',
'https://your-site.com/scheduler/webhook',
headers={
'Authorization': f'Bearer {SCHEDULER_TOKEN}'
}
)
return {
'statusCode': response.status,
'body': response.data.decode('utf-8')
}
apiVersion: batch/v1
kind: CronJob
metadata:
name: grav-scheduler
spec:
schedule: "*/5 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: scheduler-trigger
image: curlimages/curl:latest
args:
- /bin/sh
- -c
- |
curl -X POST https://your-site.com/scheduler/webhook \
-H "Authorization: Bearer ${SCHEDULER_TOKEN}" \
--fail
restartPolicy: OnFailure
Add a new monitor:
- Monitor Type: HTTP(s)
- URL:
https://your-site.com/scheduler/health
- Method: GET
- Expected Status Code: 200
- Heartbeat Interval: 60 seconds
Create a new uptime check:
- Check type: HTTP
- URL:
https://your-site.com/scheduler/health
- Check for string:
"status":"healthy"
Generate a secure token:
# Linux/Mac
openssl rand -hex 32
# Or use PHP
php -r "echo bin2hex(random_bytes(32));"
- Always use HTTPS in production
- Use strong tokens (at least 32 characters)
- Rotate tokens periodically
- Restrict access via firewall rules if possible
- Monitor access logs for suspicious activity
- Use rate limiting with a reverse proxy
http {
limit_req_zone $binary_remote_addr zone=scheduler:10m rate=1r/m;
server {
location /scheduler/webhook {
limit_req zone=scheduler burst=5;
proxy_pass http://localhost:8080;
}
}
}
- Ensure the plugin is enabled
- Check that Modern Scheduler is enabled in configuration
- Clear Grav cache:
bin/grav cache
- Verify token matches exactly (no extra spaces)
- Check token is properly configured in
scheduler.yaml
- Ensure Authorization header format:
Bearer YOUR_TOKEN
- Check cron/systemd timer is configured
- Verify scheduler is running:
bin/grav scheduler --run
- Check logs:
tail -f logs/grav.log
Enable CORS in plugin configuration:
# user/config/plugins/scheduler-webhook.yaml
enabled: true
cors: true
Use ngrok for local testing:
# Install ngrok
brew install ngrok # Mac
# or download from https://ngrok.com
# Expose local site
ngrok http 8080
# Use the ngrok URL for testing
curl -X POST https://abc123.ngrok.io/scheduler/webhook \
-H "Authorization: Bearer test-token"
Enable Grav debugging for detailed logs:
# user/config/system.yaml
debugger:
enabled: true
errors:
display: 1
log: true
log:
handler: file
syslog:
facility: local6
- Documentation: GitHub Wiki
- Issues: GitHub Issues
- Discord: Grav Discord
MIT License - see LICENSE file for details
Developed by Trilby Media for the Grav CMS community.