Search docs.molo17.com
    Operational guide Control Plane

    Automate pipeline actions with schedules, chained events, and webhooks

    Stop starting snapshots by hand. In this guide you use Schedules & events (Chronos) to run a snapshot on a clock, chain a second snapshot after the first, receive a Gluesync notification on a webhook endpoint when each snapshot ends, and start a job from outside the Control Plane with a single curl call.

    In this guide

    You will learn how to create a schedule that fires every minute and prove from the target database that it ran, change it to a nightly cron expression, chain a snapshot of orders after a snapshot of customers, empty and reload a table on a schedule and return to CDC, send the snapshot events to an HTTP endpoint with an outbound webhook, and create an event whose trigger URL starts a snapshot when an external system calls it.

    The examples use a pipeline named Chronos demo with two entities, customers and orders, that replicate the PostgreSQL tables shop.customers and shop.orders into the target schema shop_chronos.

    Quick information

    Goal

    Run pipeline actions on a schedule, in a chain, and on a webhook call, and receive Gluesync events on a webhook endpoint

    Audience

    Gluesync administrators and data engineers

    Level

    Intermediate

    Time required

    About 55 minutes

    Area

    Control Plane → Schedules & events, and Settings → Notifications → Webhooks

    Applies to

    Gluesync 2.3

    Before you begin

    Make sure that:

    1. You can sign in to the Gluesync Control Plane as a Super Admin or a Manager, the roles that can create and edit schedules and events;

    2. A pipeline named Chronos demo exists with two entities, customers and orders, whose target tables are in the schema shop_chronos. If your target does not have these tables yet, the optional first step creates them; to create the pipeline, see Pipelines;

    3. You can run SQL against the source and the target database, for example with psql;

    4. You have an HTTP endpoint that you control and that Core Hub can reach, to receive webhook calls. The examples use the WebHook Tester container, which shows every request it receives;

    5. For the command-line steps, you can run curl from a shell that reaches the Control Plane address.

    Every action in this guide runs against the Chronos demo pipeline only. Chronos stops an entity before it takes a snapshot, and with the snapshot actions an entity that was stopped stays stopped afterwards, so most steps here do not start continuous replication. To empty a table, reload it and return to CDC, see the step Schedule a snapshot with truncate, then return to CDC. If you schedule a snapshot on a pipeline in production, read Snapshot tasks first.

    Guide steps

    Optional: create the target tables

    SQL

    Skip this step if your target database already has the tables, for example in an environment you have already prepared. Otherwise, create the schema and the two tables with the same columns as the source, because Gluesync loads data into target tables that already exist.

    1. Connect to the target database;

    2. Run the following statements:

      CREATE SCHEMA IF NOT EXISTS shop_chronos;
      
      CREATE TABLE shop_chronos.customers (
        id integer PRIMARY KEY,
        full_name varchar(100) NOT NULL,
        email varchar(150),
        country varchar(2) NOT NULL,
        tier varchar(10) NOT NULL,
        status varchar(10) NOT NULL,
        credit_limit numeric(10,2),
        created_at timestamp NOT NULL
      );
      
      CREATE TABLE shop_chronos.orders (
        id integer PRIMARY KEY,
        customer_id integer NOT NULL,
        amount numeric(10,2) NOT NULL,
        currency varchar(3) NOT NULL,
        status varchar(12) NOT NULL,
        order_date date NOT NULL
      );
    3. Check that both tables are empty:

      SELECT (SELECT count(*) FROM shop_chronos.customers) AS customers,
             (SELECT count(*) FROM shop_chronos.orders)    AS orders;
    Expected result

    The query returns 0 for both tables.

    Check the scheduler time zone

    UI

    Chronos evaluates every schedule in one time zone. Check it before you create the first schedule.

    1. In the left rail, select Schedules & events;

    2. Select Schedules;

    3. Select the gear icon (Scheduler settings) above the table;

    4. Read the value of Timezone;

    5. Select Cancel to leave the setting unchanged, or select another time zone and then Save.

    Scheduler settings dialog with the Timezone field set to UTC (annotation 1) and the Save button (annotation 2)
    Figure 1. The Timezone field in Scheduler settings.
    Expected result

    You know which time zone the cron expressions you enter are interpreted in. In the examples this is UTC.

    The time zone is a setting of the whole Core Hub, and a schedule keeps the time zone it was created with: the dialog states that changing the setting does not affect schedules that already exist. The Start time and Last run columns of the table show times in your browser’s time zone, which can differ from the scheduler time zone.

    Create a schedule that runs every minute

    UI

    A short interval proves that the schedule fires without waiting for the night. You change it to a realistic expression in step 5.

    1. On the Schedules page, select New;

    2. In Name this schedule, enter Customers snapshot every minute;

    3. In Select the action that you want to be applied, select Snapshot without truncate;

    4. Select the CRON tab;

    5. Leave all five fields (Minutes, Hour, Day of the month, Month, Day of the week) set to *;

    6. In Pipeline, select Chronos demo;

    7. In Entity, select customers;

    8. Select Save.

    Add new schedule dialog with the name field (annotation 1)
    Figure 2. Name, action, cron fields, pipeline, and entity of the first schedule.
    Expected result

    The schedule appears in the Schedules table as Enabled, with * * * * * in Repeats on, the action Snapshot without truncate, and customers in Involved items.

    Snapshot without truncate loads the current source rows into the target with upsert semantics and keeps the rows that the snapshot does not replace. Snapshot with truncate clears the selected target data first. See Choose an action for the full list of actions.

    Confirm that the schedule ran and changed the target

    UI SQL

    Check the result in two places: the schedule row and the target table.

    1. Wait until the next minute starts, then reload the page;

    2. Read the Last run column of the schedule;

    3. In the target database, count the loaded rows and compare them with the source:

      SELECT count(*) AS target_customers FROM shop_chronos.customers;   -- run on the target
      SELECT count(*) AS source_customers FROM shop.customers;           -- run on the source
    4. To prove that each run reloads the data, delete a few target rows and count again after the next minute starts:

      DELETE FROM shop_chronos.customers WHERE id <= 5;
      SELECT count(*) FROM shop_chronos.customers;   -- 5 fewer than the source, for now
    5. After the next minute starts, run the count again.

    Schedules table with the Last run time (annotation 1)
    Figure 3. The Last run column shows the time of the latest execution, and Run now starts the schedule on demand.
    Expected result

    Last run shows a green check mark and the time of the latest minute. The target count equals the source count again within a minute of the delete.

    Optional, for advanced users

    If you have shell access to the Docker host, the Chronos container log also records each run. You do not need it to follow this guide:

    docker compose logs --since 5m gluesync-chronos | grep -E "Executing scheduled job|Successfully resynced"

    Each run writes one Executing scheduled job line followed by one Successfully resynced entity line.

    Chronos stops the entity, waits about five seconds, and then starts a one-time snapshot, so the rows arrive about five seconds after the minute starts. The Control Plane does not list the past runs of a schedule: use Last run and the target data. A failed run shows a red mark in Last run, and the error message appears as a tooltip on it.

    Change the schedule to a nightly cron expression

    UI

    After the test, turn the schedule into the one you would keep in production: a snapshot every night at 02:00.

    1. In the schedule row, select Edit schedule;

    2. In Name this schedule, enter Customers nightly snapshot;

    3. In Minutes, enter 0;

    4. In Hour, enter 2;

    5. Leave Day of the month, Month, and Day of the week set to *;

    6. Select Save.

    Edit CRON schedule dialog with the new name (annotation 1)
    Figure 4. Minutes 0 and hour 2 run the snapshot at 02:00 every day.
    Expected result

    Repeats on shows 0 2 * * *, and Start time shows the next 02:00 run, converted to your browser’s time zone.

    The five cron fields are read left to right:

    Field Example Meaning

    Minutes

    0

    At minute 0 of the hour.

    Hour

    2

    At 02 o’clock, in the scheduler time zone (24-hour clock).

    Day of the month

    *

    Every day of the month.

    Month

    *

    Every month.

    Day of the week

    *

    Every day of the week.

    The checkbox Run when either the day of month or the day of week matches is unavailable while at least one of the two day fields is *. It applies only when you set both. See Day of the month and day of the week for how the two fields combine.

    The Weekly Schedule tab offers the same result without cron syntax: select the days, enter a start time in hh:mm format, and choose AM or PM. When you edit a schedule that was created with a cron expression, the Weekly Schedule tab is unavailable.

    Chain a snapshot of orders after the snapshot of customers

    UI

    A chained event is an extra action that Chronos runs after the schedule’s own action. Use one to load orders right after customers.

    1. On the Schedules page, select New;

    2. In Name this schedule, enter Customers then orders;

    3. In Select the action that you want to be applied, select Snapshot without truncate;

    4. Select the CRON tab and leave the five fields set to *;

    5. In Pipeline, select Chronos demo, and in Entity select customers;

    6. Under Chained Events, select Add event;

    7. In Execution mode, keep Async (fire & forget);

    8. In Action, select Snapshot without truncate;

    9. In the Pipeline list of the chained event, select Chronos demo, and in its Entity list select orders;

    10. Select Save.

    Add new schedule dialog with the schedule name (annotation 1)
    Figure 5. The first action loads customers; the chained event loads orders after it.
    1. Before the next minute starts, delete rows from both target tables:

      DELETE FROM shop_chronos.customers WHERE id <= 20;
      DELETE FROM shop_chronos.orders WHERE id <= 100;
    2. After the next run, count the rows again;

    3. In the schedule row, select Disable schedule so that the chain stops firing every minute.

    Schedules table with the nightly schedule enabled and its cron expression (annotation 1)
    Figure 6. Expand the row to see the chained event. The every-minute chain is disabled; the nightly schedule stays enabled.
    Expected result

    Both target tables hold all the source rows again. The chained schedule shows Disabled, and its row has a chain badge with the number of chained events. To see the order in which the steps ran without leaving the Control Plane, send the snapshot events to a webhook, as shown in the next step.

    Optional, for advanced users

    With shell access to the Docker host, the Chronos container log shows the order of the chain: docker compose logs --since 5m gluesync-chronos | grep -E "Executing chained events|Chained event pos|Successfully resynced". The customers entity is resynced first and the orders entity about seven seconds later, after the line Chained event pos=0 …​ mode=ExecutionMode.ASYNC.

    Execution mode What Chronos does

    Async (fire & forget)

    Starts the chained action right after Chronos has started the previous action, and does not wait for the previous action to finish.

    Sync (wait for completion)

    Waits for the Core Hub completion event of the previous step, up to Webhook timeout (seconds) (default 3600), and then starts the chained action. If the event does not arrive in time, Chronos stops the chain and records the error on the schedule.

    Prefer Async for short snapshots. Chronos starts listening for the completion event only after the previous action has returned, about two seconds after the snapshot was started, so a sync step that follows a snapshot that finishes sooner than that waits until the timeout. A sync step also listens for events of its own pipeline, group, and entity: it is released only by an event of the entity that the chained action targets, so a chain from a customers snapshot to an orders snapshot does not work in sync mode. Sync mode fits a step that follows a long-running action on the same entity, for example a snapshot of a large table followed by another action on that table.

    Schedule a snapshot with truncate, then return to CDC

    UI SQL

    Use this when a table must be emptied and reloaded on a schedule, for example every night, and live replication must keep running afterwards. One action does both: Snapshot with truncate + CDC. Do not build it from Snapshot with truncate and a chained CDC event: the table below shows why it fails.

    The entity customers can be stopped or running in CDC when the schedule fires. In this guide it is stopped, as the previous steps left it.

    1. Optional, to see the truncate at work: add a row to the target that does not exist in the source:

      INSERT INTO shop_chronos.customers (id, full_name, country, tier, status, created_at)
      VALUES (99999, 'Stale row, not in the source', 'IT', 'gold', 'active', now());   -- run on the target
    2. On the Schedules page, select New;

    3. In Name this schedule, enter Customers truncate and CDC every minute;

    4. In Select the action that you want to be applied, select Snapshot with truncate + CDC;

    5. Select the CRON tab and leave all five fields set to *;

    6. In Pipeline, select Chronos demo, and in Entity select customers;

    7. Leave Chained Events empty and select Save.

    Add new schedule dialog with the name (annotation 1)
    Figure 7. One schedule, one action: Snapshot with truncate + CDC. No chained event.
    1. Wait until the next minute starts, reload the page, and read the Action and Last run columns of the schedule:

    Schedules table with the action Snapshot with truncate + CDC (annotation 1)
    Figure 8. The action tag reads Snapshot with truncate + CDC and Last run shows a green check mark.
    1. In the target database, check that the extra row is gone and that the counts match:

      SELECT count(*) AS target_customers,
             count(*) FILTER (WHERE id = 99999) AS stale_rows
      FROM shop_chronos.customers;                                   -- run on the target
      SELECT count(*) AS source_customers FROM shop.customers;       -- run on the source
    2. Open the pipeline Chronos demo and look at the customers entity:

    Chronos demo pipeline with the customers entity in the Active section
    Figure 9. After the run, customers is in the Active section, in CDC. The orders entity was not part of the schedule and stays on hold.
    1. Prove that live changes flow: insert a row in the source, wait a few seconds, and look for it in the target:

      INSERT INTO shop.customers (id, full_name, email, country, tier, status, credit_limit, created_at)
      VALUES (9601, 'Added after the schedule', 'after@example.com', 'DE', 'silver', 'active', 500, now());   -- run on the source
      
      SELECT id, full_name FROM shop_chronos.customers WHERE id = 9601;                                         -- run on the target
    2. In the schedule row, select Disable schedule so that the table is not emptied and reloaded every minute.

    Expected result

    After the run the extra row 99999 is gone and the target holds exactly the source rows (we saw 200 on both sides): the target was truncated and reloaded. customers is in the Active section of the pipeline, so CDC is running, and the row 9601 inserted in the source after the run arrives in the target within seconds. The schedule shows Disabled. For a production schedule, edit it to a nightly expression as in step 5.

    The rest of this step explains the result. Snapshot with truncate stops the entity, waits about five seconds, and starts a one-time snapshot with the write method INSERT, which empties the target table before the first row is written. When the snapshot ends, Core Hub starts CDC again only for an entity that was in CDC when the snapshot started, and Chronos has just stopped it, so the entity stays stopped. The action Snapshot with truncate + CDC asks Core Hub for a re-sync instead: Chronos pauses the entity and waits until it has left the active state, then Core Hub empties the table, copies the rows, and starts CDC by itself. We ran each setup on customers (200 rows) and on a table of 1.5 million rows, whose snapshot takes between 25 and 60 seconds:

    Schedule Table of 200 rows Table of 1.5 million rows

    Snapshot with truncate

    Target reloaded. The entity stays stopped: a source INSERT after the run never arrives.

    Same.

    Snapshot with truncate, chained event CDC in Async (fire & forget) mode

    Works, but only because the snapshot ended before Chronos sent the start command.

    The start command reaches Core Hub while the snapshot is still running and is refused. The entity ends stopped and nothing in the Control Plane says so.

    Snapshot with truncate, chained event CDC in Sync (wait for completion) mode

    The chain waits for a completion event that was sent before Chronos started listening, and times out after Webhook timeout (seconds) (30 seconds in our test). Last run shows Chained event pos=0 (TaskType.ENTITY_START) failed or timed out. The entity stays stopped.

    Works: the snapshot lasts longer than the two seconds Chronos needs to start listening.

    Snapshot with truncate + CDC

    Works.

    Works.

    A green mark in Last run only means that Core Hub accepted the command. A schedule whose chained CDC start was refused still shows a green mark. Always check that the entity is in the Active section and that a new source row reaches the target.

    Changes made on the source while the snapshot runs are not lost: an INSERT and two UPDATE statements run during a snapshot of 1.5 million rows were all in the target after CDC started.

    Send snapshot events to an outbound webhook

    UI

    Chronos has no action that calls an HTTP endpoint. To be notified when a scheduled snapshot ends, use a Core Hub webhook: Gluesync posts a CloudEvents JSON document to your endpoint for every matching event. This also shows the order of the chain from the receiver’s side.

    1. Open the receiver and copy its endpoint URL. In WebHook Tester, create a session and copy the address that Core Hub must call, for example http://webhook-tester:8080/<session-uuid>;;

    2. In the Control Plane, select the gear icon (Settings) in the top bar;

    3. Select Notifications, then the Webhooks tab;

    4. Select Add webhook;

    5. In Name, enter Chronos demo to webhook tester;

    6. In Endpoint URL, enter the receiver address;

    7. In Description (optional), enter a short note.

    New webhook form with the Name field (annotation 1) and the Endpoint URL field (annotation 2)
    Figure 10. Name and endpoint of the new webhook.
    1. Scroll down to Objects filters, and in Pipeline select Chronos demo;

    2. In Enabled events, select Entity Snapshot Started, Entity Snapshot Completed, and Entity Snapshot Failed;

    3. Next to Severity filter, select Select all;

    4. Select Send test;

    5. Select Create webhook.

    Webhook form with the pipeline filter (annotation 3)
    Figure 11. Limit the webhook to one pipeline, three events, and all severities.
    1. Open Schedules & events > Schedules and, in the Customers then orders row, select Run now;

    2. Open the receiver and select the newest request.

    WebHook Tester with the list of four received requests (annotation 1) and the JSON body of the latest request (annotation 2)
    Figure 12. The receiver lists four requests, oldest at the bottom; the newest is the end of the orders snapshot.
    Expected result

    After Send test, the receiver shows a request of type gluesync.webhook.test. After Run now, the receiver shows four requests whose type and entityName fields give this order: gluesync.entity.snapshot.started and gluesync.entity.snapshot.completed for customers, then the same two events for orders, about seven seconds later. Each request carries the headers X-Gluesync-Event and X-Gluesync-Delivery.

    The body of the last request looks like this:

    {
      "specversion": "1.0",
      "id": "88659f47-af5b-4b5a-8416-390e51314c00",
      "source": "gluesync",
      "type": "gluesync.entity.snapshot.completed",
      "time": "2026-10-28T11:47:36.158275333Z",
      "datacontenttype": "application/json",
      "severity": "INFO",
      "pipelineId": "5b107155",
      "pipelineName": "Chronos demo",
      "entityId": "1696b31b",
      "entityName": "orders",
      "message": "Snapshot task for orders ended in pipeline Chronos demo at 11:47 10-28-2026 in 37 ms",
      "eventSource": { "kind": "entity", "id": "1696b31b" },
      "data": { "source": { "kind": "entity", "id": "1696b31b" } }
    }

    The Severity filter decides which events are delivered, and a webhook with an empty Severity filter delivers none of the events that you selected, although Send test still succeeds. Select all three severities, or only the ones you want.

    The Webhooks tab also lists rows named chronos-event-<number> that Chronos creates and removes by itself for its sync chained events. Do not edit them. For signing, custom headers, delivery logs, and dead letters, see Webhook alerting. Use HTTPS endpoints in production.

    Start a job from outside with an inbound webhook

    UI CLI

    An event with a Webhook trigger gets its own URL and secret token. Any system that can send an HTTP POST request, such as a CI job or an orchestrator, can then start the event’s action.

    1. Select Schedules & events, then Events;

    2. Select New;

    3. In Name, enter Refresh customers on demand;

    4. Select the Webhook trigger tab;

    5. In Description (optional), enter a short note;

    6. Under Chained Events, select Add event;

    7. In Action, select Snapshot without truncate;

    8. In Pipeline, select Chronos demo, and in Entity select customers;

    9. Select Save.

    New event dialog with the name (annotation 1)
    Figure 13. A webhook-triggered event with one action.
    1. In the Trigger flow created — save your token dialog, select the copy icon next to Secret token and store the token in a password manager or secret store;

    2. Copy the Trigger URL;

    3. Select Done.

    Trigger flow created dialog with the secret token (annotation 1)
    Figure 14. The secret token is shown once, together with the trigger URL.
    1. Delete some rows from the target table, so that the effect is visible:

      DELETE FROM shop_chronos.customers WHERE id <= 20;
    2. From a shell, call the trigger URL with the token in the X-Trigger-Token header. Use -k only if the Control Plane has a self-signed certificate:

      curl -k -i -X POST "https://<control-plane-address>/chronos/api/triggers/1/fire" \
        -H "X-Trigger-Token: <secret-token>"
    3. Count the target rows again after a few seconds, and select the expand arrow of the event in the Events table.

    Events table with the Fire now button (annotation 1)
    Figure 15. The event’s log lists each run with its result, its source (webhook or manual), the time, and the duration.
    Expected result

    curl answers HTTP/2 202 with a body that includes "status":"queued" and "events_count":1. A few seconds later the target holds all the source rows again, and the event log has a row with the result success and the source webhook. If you also select Fire now (the lightning icon in the Actions column), the log gets a row with the source manual; Fire now needs no token.

    Add ?wait=true&wait_timeout_seconds=60 to the URL to make the call wait until the action has been started and answer 200 with "status":"completed", which suits a CI step that must not continue before the action has finished starting. A wrong or missing token returns 401 with Invalid token or TriggerFlow not found, and a disabled event returns 403.

    Understand where each result is visible

    What you want to know Where to look What you see

    Did the schedule fire?

    Last run column on the Schedules page

    Time of the latest run, a green or red mark, and the error text for a failed run.

    Did the data arrive?

    SQL on the target tables

    Row counts equal to the source.

    In which order did the chain run?

    Requests received by an outbound webhook

    The customers events come first, then the orders events, with timestamps.

    Did an external call start the event?

    Event log in Schedules & events > Events

    One row per run with the source webhook or manual.

    Did Gluesync deliver the webhook?

    Settings > Notifications > Webhooks, Delivery logs

    One row per delivery with its HTTP status.

    Verify the result

    You have successfully automated the pipeline if:

    • The Customers nightly snapshot schedule is Enabled and shows 0 2 * * * in Repeats on;

    • The Customers then orders and Customers truncate and CDC every minute schedules are Disabled, so that no every-minute schedule is still firing;

    • After a run of the chain, the target tables shop_chronos.customers and shop_chronos.orders hold all the source rows;

    • After a run of Snapshot with truncate + CDC, the extra target row is gone, customers is in the Active section, and a row inserted in the source afterwards reaches the target;

    • Your webhook endpoint received the snapshot events of customers before those of orders;

    • The Refresh customers on demand event log has a row with the source webhook.

    Troubleshooting

    Problem Possible cause What to do

    The schedule never shows a Last run

    The schedule is Disabled, or the next run has not been reached

    Select Enable schedule, check Start time for the next run in your browser’s time zone, or select Run now to test the action.

    The schedule runs at the wrong hour

    The cron expression is read in the scheduler time zone, not in your browser’s

    Check Timezone in Scheduler settings. A schedule keeps the time zone it was created with, so create it again after changing the setting.

    The snapshot ran but the target is empty

    The target table does not exist or has different columns

    Create the tables as in step 1, and read the notifications in the Control Plane for the error.

    A sync chained event never starts and the schedule records failed or timed out

    The previous step finished before Chronos started listening, or it ran on a different entity than the chained step

    Use Async (fire & forget), or use sync mode only after a long-running action on the same entity. Hover over the red mark in Last run to read the error, for example Chained event pos=0 (TaskType.ENTITY_SNAPSHOT) failed or timed out.

    The webhook receives nothing after Run now

    Severity filter is empty, the event types do not match, or the Objects filters exclude the pipeline

    Select all severities, check Enabled events, and check that Pipeline is Chronos demo. Look at Delivery logs under Settings > Notifications > Webhooks.

    Send test does not reach the receiver

    The endpoint is not reachable from Core Hub

    Use the address that Core Hub can resolve. From a container, use the receiver’s container name and its internal port, not localhost.

    After a Snapshot with truncate run the target is reloaded, but the entity is stopped and new source rows never arrive, although Last run is green

    Snapshot with truncate does not return the entity to CDC, and a chained CDC event is either refused while the snapshot is still running (Async) or times out for a short snapshot (Sync)

    Edit the schedule: choose the action Snapshot with truncate + CDC, with no chained event. To recover now, select Start sync on the entity. Check the Active section of the pipeline after every run.

    Snapshot with truncate + CDC leaves rows in the target that are not in the source

    The setting Disable truncate on target table before snapshot inserts of the target agent is on, so the table is not emptied

    Turn the setting off in the advanced settings of the target agent and run the schedule again. We checked it with a stale row: with the setting on, the row stayed in the target after the run.

    curl answers 401

    The token is wrong, missing, or was regenerated

    Copy the token again. If you lost it, regenerate it from the event in the Events table.

    curl answers 403

    The event is disabled

    Enable the event in the Events table.

    Contact MOLO17 Support if you need assistance with schedules, events, or webhooks.