4dauby/schedyt

By 4dauby

Updated 25 days ago

Schedyt is a simple service for scheduling events.

Image
Message queues
Databases & storage
1

565

4dauby/schedyt repository overview

Overview

Schedyt schedules events based on the provided time zone, ensuring that scheduled tasks are executed according to the specified region's time. You can find the complete list of frequently used short time-zone names here.

Schedyt is a simple service for scheduling events. An event can be a task, a note, a message, or other types of activities. Events can be scheduled:

  • Once: For a single occurrence.
  • At a fixed rate: Repeated at regular intervals.
  • Over a period: Within a defined time range.
  • Indefinitely: For ongoing, never-ending repetitions.

Additionally, Schedyt supports RabbitMQ Direct Exchange, enabling precise message routing to specific queues based on routing keys.

architecture

Use Cases: Scheduled notifications, event-driven workflows, time-based campaigns

how it works

⚠️ SECURITY WARNING

CRITICAL - READ BEFORE DEPLOYMENT:

  1. Change default admin credentials (Application: schedyt, Password: Pas5w.rd)

    • Set via ADMIN_SECRET environment variable
    • Auto-created when using prod-api-key or prod-http-basic profiles
  2. Change default passwords in examples (database, RabbitMQ)

  3. Never use quick-start profile in production - NO AUTHENTICATION

  4. Always use HTTPS in production with either prod-http-basic or prod-api-key (recommended)

  5. Secure your RabbitMQ instance with strong credentials and network isolation

Example:

environment:
  ADMIN_SECRET: YourVeryStrongAdminPassword123!

Application Profiles

Available Profiles

Security Profiles (choose one):

ProfilePurposeFeaturesUse Case
quick-startDevelopment⚠️ No auth, H2 embedded DB, console loggingLocal dev, demos
prod-http-basicProductionHTTP Basic AuthenticationInternal services, simple auth
prod-api-keyProduction ⭐API key authenticationExternal APIs, multiple clients

Note: quick-start is fully self-contained — it always runs with an embedded H2 database and must not be combined with a database profile (mariadb, mysql, postgresql).

Database Profiles (required for production):

ProfilePurposeFeaturesUse Case
mariadbDatabaseMariaDB 10.4+Production database
mysqlDatabaseMySQL 8.0+Production database
postgresqlDatabasePostgreSQL 12+Production database

Profile Activation

v1.0.x: Single profile only

JAVA_OPTS: -Dspring.profiles.active=prod-api-key

v1.1.x+: Security + Database (except quick-start)

JAVA_OPTS: -Dspring.profiles.active=postgresql,prod-api-key

Roles

RolePermissionsNotes
CLIENTManage own events onlyDefault for new applications
ADMINFull access to all applications and eventsAuto-created on first start with prod-* profiles

Default ADMIN Credentials:

  • Application: schedyt
  • Password: Pas5w.rd
  • ⚠️ Change via ADMIN_SECRET environment variable

Admin Application ID (fixed, never changes):

74894a2088394cb7acdc700a85f0443d

Use this ID to generate or retrieve the admin API key via the X-APP-SECRET header:

# Retrieve admin API key (prod-api-key profile)
curl -X GET 'http://localhost:8080/v1/applications/74894a2088394cb7acdc700a85f0443d/keys' \
  --header 'X-APP-SECRET: Pas5w.rd'
{
    "applicationId": "74894a2088394cb7acdc700a85f0443d",
    "applicationName": "schedyt",
    "apiKey": "<your-admin-api-key>",
    "updatedAt": "..."
}

Use the returned apiKey as the X-API-KEY header value for all subsequent admin requests.

Getting Started

Requirements

  • Docker
  • curl or Postman for API testing

Configuration Guide

Use CaseProfile(s)SecurityDatabaseWhen to Use
Development/Testingquick-start⚠️ NoneH2 (embedded)Local dev, testing, demos
Production (Simple)prod-http-basic + DBHTTP Basic AuthExternal DB requiredInternal services, trusted networks
Production (Recommended)prod-api-key + DBAPI KeyExternal DB requiredMultiple clients, external APIs, enhanced security

Database Options (Production only): mariadb, mysql, postgresql

Version-Specific Requirements:

  • v1.0.x: Single profile only (database embedded in security profiles, MariaDB only)
  • v1.1.x+: Two profiles required (security + database), except quick-start which remains standalone

Running Schedyt

Prerequisites
docker network create schedyt-network
Quick Start (Development Only)

⚠️ NO AUTHENTICATION - Development only

# RabbitMQ
docker run -d \
  --network schedyt-network \
  --hostname schedyt-broker \
  --name schedyt-broker \
  -p 5672:5672 \
  -p 15672:15672 \
  --env RABBITMQ_DEFAULT_USER=kageyama \
  --env RABBITMQ_DEFAULT_PASS=k@geSecre7 \
  rabbitmq:3.12.4-management-alpine

# Schedyt
docker run -d \
  --network schedyt-network \
  --name schedyt-app \
  --env JAVA_OPTS=-Dspring.profiles.active=quick-start \
  --env BROKER_HOST=schedyt-broker \
  -p 8080:8080 \
  4dauby/schedyt:latest
PostgreSQL + API Key Setup
# RabbitMQ
docker run -d \
  --network schedyt-network \
  --hostname schedyt-broker \
  --name schedyt-broker \
  -p 5672:5672 \
  -p 15672:15672 \
  --env RABBITMQ_DEFAULT_USER=kageyama \
  --env RABBITMQ_DEFAULT_PASS=k@geSecre7 \
  rabbitmq:3.12.4-management-alpine

# PostgreSQL
docker run -d \
  --network schedyt-network \
  --hostname schedyt-db \
  --name schedyt-db \
  --env POSTGRES_USER=dbUser \
  --env POSTGRES_PASSWORD=my-secret-pwd \
  --env POSTGRES_DB=schedyt_db \
  postgres:17-alpine3.22

# Schedyt
docker run -d \
  --network schedyt-network \
  --name schedyt-app \
  --env JAVA_OPTS=-Dspring.profiles.active=postgresql,prod-api-key \
  --env DB_HOST=schedyt-db \
  --env SCHEDYT_DB_USER=dbUser \
  --env SCHEDYT_DB_PASSWORD=my-secret-pwd \
  --env BROKER_HOST=schedyt-broker \
  --env BROKER_USER=kageyama \
  --env BROKER_PASSWORD=k@geSecre7 \
  --env ADMIN_SECRET=YourSecureAdminPassword123! \
  -p 8080:8080 \
  4dauby/schedyt:latest

For MySQL or MariaDB: Replace the database container and update profile:

DatabaseImageProfile
MySQLmysql:8.0mysql,prod-api-key
MariaDBmariadb:10.4.4mariadb,prod-api-key

Note: Use MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE environment variables for MySQL/MariaDB

Container Management
# View logs
docker logs schedyt-app
docker logs schedyt-db
docker logs schedyt-broker

# Stop containers
docker stop schedyt-app schedyt-db schedyt-broker

# Remove containers
docker rm schedyt-app schedyt-db schedyt-broker

# Remove network
docker network rm schedyt-network

Schedule Your First Event

Step 1: Register an Application
curl --location 'http://localhost:8080/v1/applications' \
--header 'Content-Type: application/json' \
--data '{
  "name":"my_application_test",
  "description":"My scheduling application",
  "exchangeName":"quick_exchange",
  "secret": "MySecureSecret123!",
  "zoneId":"Africa/Abidjan"
}'

Response Example:

{
  "id": "9779548b335c470096c6bc6863348af9",
  "name": "my_application_test",
  "description": "My scheduling application",
  "exchangeName": "quick_exchange",
  "zoneId": "Africa/Abidjan",
  "createdAt": "2026-06-14 03:33:51 GMT"
}

Profile-Specific Values:

  • quick-start: exchangeName must be quick_exchange
  • Production: Use your custom exchange name

Save the id - you'll need it for scheduling events.

Step 2: Schedule an Event

Replace {application_id} with the ID from Step 1.

curl --location 'http://localhost:8080/v2/applications/{application_id}/schedules' \
--header 'Content-Type: application/json' \
--data '{
  "eventName":"Test Notification",
  "triggerDate": {
    "year": 2025,
    "month": 10,
    "day": 24,
    "hour": 14,
    "minute": 30,
    "second": 0
  },
  "zoneId":"Africa/Abidjan",
  "frequency":0,
  "duration":0,
  "event":{
    "content":"Event successfully scheduled and triggered"    
  },
  "routingKey":"quick_start"
}'

Response Example:

{
  "scheduleId": 1,
  "eventName": "Test Notification",
  "zoneId": "Africa/Abidjan",
  "createdAt": "2025-10-23 08:04:43 GMT",
  "triggerDate": "2025-10-24 14:30:00 GMT",
  "frequency": 0,
  "duration": 0,
  "triggerFirstAt": null,
  "event": {
    "content": "Event successfully scheduled and triggered"
  },
  "application": {
    "id": "391f25426ad14f9f9bcfeac3725afc33",
    "name": "my_application_test"
  },
  "routingKey": "quick_start"
}

Profile-Specific Values:

  • quick-start: routingKey must be quick_start
  • Production: Use routing key matching your RabbitMQ queue bindings

Tip: Set triggerDate 2-3 minutes in the future for quick testing.

Step 3: View the Event

For quick-start profile - Check container logs:

docker logs schedyt-app

Expected output when event triggers:

[QUICK START][INFO] Event received: {"content":"Event successfully scheduled and triggered"}

For Production profiles - Consume from RabbitMQ:

  1. Access RabbitMQ Management: http://localhost:15672 (credentials from your setup)
  2. Create a queue and bind it to your exchange with your routing key
  3. Implement a consumer in your application

Python Consumer Example:

#!/usr/bin/env python
import pika
from pika.credentials import PlainCredentials

credentials = PlainCredentials("rabbitUser", "my-secret-pwd")
connection = pika.BlockingConnection(
    pika.ConnectionParameters(host='localhost', credentials=credentials))
channel = connection.channel()

channel.exchange_declare(exchange='events_exch', exchange_type='topic')
result = channel.queue_declare('', exclusive=True)
queue_name = result.method.queue

# Bind with your routing key
channel.queue_bind(exchange='events_exch', queue=queue_name, routing_key='your.routing.key')

print(' [*] Waiting for events. Press CTRL+C to exit')

def callback(ch, method, properties, body):
    print(f" [x] {method.routing_key}: {body}")

channel.basic_consume(queue=queue_name, on_message_callback=callback, auto_ack=True)
channel.start_consuming()
Postman Alternative
  1. Download collection: schedyt.postman_collection.json
  2. Import to Postman
  3. Use Register Application [Public]Schedule Event [Client] v2 requests

Deploy via Docker Compose

services:

  schedyt-db:
    container_name: schedyt-db
    image: postgres:17-alpine3.22
    restart: always
    environment:
      POSTGRES_USER: userDb
      POSTGRES_PASSWORD: my-secret-pwd
      POSTGRES_DB: schedyt_db
      POSTGRES_INITDB_ARGS: '--data-checksums'
    command: |
      postgres -c shared_preload_libraries=pgcrypto
    ports:
      - '5432:5432'

  schedyt-broker:
    container_name: schedyt-broker
    image: rabbitmq:3.12.4-management-alpine
    environment:
      RABBITMQ_DEFAULT_USER: kageyama
      RABBITMQ_DEFAULT_PASS: k@geSecre7
    ports:
      - "5672:5672"
      - "15672:15672"

  schedyt-playground:
    container_name: 4dauby/schedyt-playground
    image: schedyt-playground:latest
    depends_on:
      - schedyt-broker
    environment:
      RABBITMQ_HOST: schedyt-broker
      RABBITMQ_VHOST: /
      RABBITMQ_PORT: 5672
      RABBITMQ_USER: kageyama
      RABBITMQ_USER_PASSWORD: k@geSecre7
      RABBITMQ_EXCHANGE_NAME: playground_exchange
      RABBITMQ_QUEUE: q.playground
      RABBITMQ_ROUTING_KEY: event.playground.*
    ports:
      - 3001:3001

  schedyt-app:
    container_name: schedyt-app
    image: 4dauby/schedyt:latest
    restart: on-failure
    environment:
      JAVA_OPTS: -Dspring.profiles.active=postgresql,prod-api-key
      DB_HOST: schedyt-db
      SCHEDYT_DB_USER: userDb
      SCHEDYT_DB_PASSWORD: my-secret-pwd
      BROKER_HOST: kageyama
      BROKER_USER: k@geSecre7
      BROKER_PASSWORD: my-secret-pwd
      ADMIN_SECRET: YourSecureAdminPassword123!
    ports:
      - "8080:8080"
    depends_on:
      - schedyt-db
      - schedyt-broker

networks:
  default:
    name: schedyt-net

About schedyt-playground: An example client application for Schedyt. It binds a queue (q.playground) to the playground_exchange exchange with routing key event.playground.* and displays triggered events in real-time at http://localhost:3001 — it doesn't do anything else with the events it receives.

Sending Events to schedyt-playground

schedyt-playground listens on a fixed exchange and routing key pattern:

ParameterValue
exchangeNameplayground_exchange
routingKeyevent.playground.*
queueq.playground

To send events to it, your application must use the same exchange, and your schedule must use a routing key matching event.playground.<key>.

Step 1 — Register your application with playground_exchange as exchange:

curl -X POST 'http://localhost:8080/v1/applications' \
  --header 'Content-Type: application/json' \
  --data '{
    "name": "playground-app",
    "description": "quick test",
    "exchangeName": "playground_exchange",
    "secret": "myPass",
    "zoneId": "Africa/Abidjan"
}'

Step 2 — Schedule an event with a routing key matching event.playground.<key>:

curl -X POST 'http://localhost:8080/v2/applications/{your-app-id}/schedules' \
  --header 'Content-Type: application/json' \
  --header 'X-API-KEY: <your-api-key>' \
  --data '{
    "eventName": "my first event",
    "triggerFirstAt": {
        "year": 2025,
        "month": 10,
        "day": 24,
        "hour": 16,
        "minute": 2,
        "second": 5
    },
    "zoneId": "Africa/Abidjan",
    "frequency": 1,
    "duration": 6,
    "event": {
        "theme": "schedyt",
        "content": "Schedyt is the best",
        "where": "Abidjan"
    },
    "routingKey": "event.playground.meeting"
}'

The routingKey must start with event.playground. — the suffix (here meeting) is free. Once the schedule fires, the event appears in real-time at http://localhost:3001.

Commands:

docker-compose up -d           # Start services
docker-compose logs -f         # View logs
docker-compose down            # Stop services

Environment Variables

VariableDescriptionDefault ValueRequired
DB_HOSTDatabase hostlocalhostYes
DB_PORTDatabase port3306 (MariaDB/MySQL), 5432 (PostgreSQL)No
SCHEDYT_DB_USERDatabase usernameschedytYes (production only)
SCHEDYT_DB_PASSWORDDatabase passwordPas5wr.dYes (production only)
BROKER_HOSTRabbitMQ hostlocalhostYes
BROKER_USERRabbitMQ usernamekageyamaYes (production only)
BROKER_PASSWORDRabbitMQ passwordk@geSecre7Yes (production only)
BROKER_PORTRabbitMQ port5672No
ADMIN_SECRETAdmin passwordPas5w.rdYes (production only)

Troubleshooting

Common Issues

1. Cannot connect to database

Symptoms: Error messages like "Connection refused" or "Unknown host"

Solutions:

  • Verify database container is running: docker ps
  • Check database host and port in environment variables
  • Ensure containers are on the same Docker network
  • Verify database credentials match between Schedyt and database configurations:
    • For PostgreSQL:
      • SCHEDYT_DB_USER must match POSTGRES_USER
      • SCHEDYT_DB_PASSWORD must match POSTGRES_PASSWORD
      • POSTGRES_DB must be set to schedyt_db
    • For MariaDB or MySQL:
      • SCHEDYT_DB_USER must match MYSQL_USER
      • SCHEDYT_DB_PASSWORD must match MYSQL_PASSWORD
      • MYSQL_DATABASE must be set to schedyt_db
  • View database logs for more details: docker logs schedyt-db
2. RabbitMQ connection failed

Symptoms: "Failed to connect to RabbitMQ" errors

Solutions:

  • Verify RabbitMQ container is running: docker ps
  • Check RabbitMQ credentials match BROKER_USER and BROKER_PASSWORD
  • Access RabbitMQ Management UI: http://localhost:15672
  • View RabbitMQ logs: docker logs schedyt-broker
3. Authentication fails (401 Unauthorized)

Symptoms: "Invalid username or password" or "Unauthorized" errors

Solutions:

  • For prod-http-basic: Use correct application name and secret in Basic Auth header
  • For prod-api-key: Verify API key is correctly set in request headers
  • Check if you're using the correct profile (prod-http-basic vs prod-api-key)
  • Verify application was created successfully
4. Events not triggering

Symptoms: Scheduled events don't execute at the specified time

Solutions:

  • Verify triggerDate is in the future and correctly formatted
  • Check time zone (zoneId) matches your expectations
  • View Schedyt logs: docker logs schedyt-app
  • Ensure RabbitMQ connection is active
  • Check if the queue is bound to the exchange with correct routing key
5. Health check failures

Symptoms: Container keeps restarting

Solutions:

  • Check application logs: docker logs schedyt-app
  • Verify all required environment variables are set
  • Ensure database is accessible before Schedyt starts
  • Increase health check timeout in docker-compose.yml

Getting Help

If you encounter issues not covered here:

  1. Check the GitLab Issues for similar problems
  2. Review application logs via docker logs
  3. Create a new issue on GitLab with:
    • Schedyt version
    • Active profiles
    • Error messages and logs
    • Steps to reproduce

Quick Reference

License

This project is licensed under Apache License Version 2.0. See the LICENSE for details.

Tag summary

Content type

Image

Digest

sha256:4f3989345

Size

125.7 MB

Last updated

25 days ago

docker pull 4dauby/schedyt:1.1.2