Back to Documentation

StepwiseRPA: Schedule Processing and Bot Run Creation

1. Overview

This document details the process of Bot Run Creation in the StepwiseRPA application, based on existing schedules.

The provided code does not cover the creation of the schedule records themselves (e.g., via a UI or admin panel). Instead, it describes a backend process responsible for:

  1. Triggering the processing of schedules via an API endpoint.
  2. Fetching active schedules from the database.
  3. Calculating upcoming run times based on recurrence rules.
  4. Creating (inserting) the individual bot_run records into the database.

This process is what "materializes" a Schedule (a definition) into BotRun instances (concrete jobs to be executed).

Core Components & Libraries

  • Next.js API Route (/api/bot-runs): The main entrypoint for the process, likely triggered by an external scheduler (e.g., a cron job).
  • Supabase: The database provider. The code interacts with it via RPC calls (get_schedules_for_bot_runs) and standard table operations (insert, delete).
  • rrule.js: A library used to parse and compute recurrence rules from iCalendar RRULE strings (stored in schedule.schedule_data).
  • luxon: A library for all date, time, and timezone management. This is critical for handling schedules across different timezones.

2. Process Flow: From Trigger to Run Creation

The process begins when a request is made to the API endpoint and flows through the server-side action functions.

Step 1: API Endpoint Trigger

The entire process is initiated by a GET request to the /api/bot-runs endpoint.

File: app/api/bot-runs/route.ts

  1. Authentication: The endpoint is designed to be protected by an API key (x-api-key).

    Note: The API key check is currently bypassed in the provided code (if (1 === 1)). In a production environment, this would be if (!apiKey || apiKey !== expectedApiKey).

  2. Fetch Schedules: It calls the Supabase RPC get_schedules_for_bot_runs. This function (whose definition is not in the files) is assumed to return a list of all active schedules that are due for processing.
  3. Iterate and Delegate: The code loops through each schedule returned from the RPC.
    • If schedule.is_recurring is true, it calls createRecurringBotRunsForSchedule(schedule).
    • The logic for non-recurring schedules (createOneTimeBotRunForSchedule) is currently commented out in this file.

Step 2: Processing Recurring Schedules

This is the core logic for generating bot_run instances from a recurring schedule.

File: app/actions/bot-runs/bot-run-actions.ts Function: createRecurringBotRunsForSchedule(scheduleForBotRun)

  1. Guard Clauses: The function first checks if the schedule is valid and active. It will exit immediately if:

    • scheduleForBotRun is null.
    • scheduleForBotRun.is_active is false.
    • scheduleForBotRun.is_recurring is false.
  2. Define Time Window: It calculates a "look-ahead" window to generate runs for.

    • nowPlus4: The current time.
    • tomorrow: The start of the day, two days from now (nowPlus4.plus({ days: 2 }).startOf('day')).
    • Result: The window effectively covers "today" and "tomorrow", ensuring runs are created in advance.
  3. Idempotency (Delete Future Runs): To prevent duplicate bot_run records if this script runs multiple times, it first deletes any existing bot_runs for this schedule within the calculated window.

    await supabase.from('bot_runs').delete()
      .eq('schedule_id', scheduleForBotRun.id)
      .gte('date_scheduled', nowPlus4.toISO()!);
    
  4. Parse Recurrence Rule: It parses the schedule.schedule_data string (e.g., FREQ=DAILY;BYHOUR=10;BYMINUTE=0) into an RRule object.

    const rrule = RRule.fromString(scheduleForBotRun.schedule_data);
    
  5. Get Base Events: It uses the rrule object to find all "base" run times within the calculated time window.

    const events = rrule.between(nowPlus4.toJSDate(), tomorrow.toJSDate(), true);
    

    Example: If the rule is "every day at 10:00 AM," events will contain a Date object for 10:00 AM today and 10:00 AM tomorrow (if they fall within the window).

  6. Create Runs (Outer Loop): The code iterates through each event found.

  7. Handle Intra-Day Repetition (Inner Loop): A schedule can have a base event (e.g., "run at 9:00 AM") and also a "repeat" setting (e.g., "repeat every 15 minutes for 2 hours"). This is handled by an inner while loop.

    • startTimeForIteration: Initialized to the event time, respecting the schedule's timezone.
    • endTime: Calculated by adding schedule.repeat_hours to the startTimeForIteration.
    • The while (startTimeForIteration <= endTime) loop continues to generate runs.
  8. Insert Bot Run: Inside the inner loop, a botRun object is constructed.

    • status: Set to 'scheduled'.
    • date_scheduled: Set to the startTimeForIteration.
    • date_expire: Calculated by adding schedule.runs_expire_value (in minutes) to the startTimeForIteration.
    • This object is then inserted into the bot_runs table.
  9. Increment for Next Repetition: If schedule.repeat_minutes is set, it is added to the startTimeForIteration, and the inner while loop runs again. If repeat_minutes is not set, the loop breaks, and the code moves to the next base event.


3. Other Key Functions

The provided files contain other functions related to bot runs.

createBotRunForSingleRunSchedule

This function is similar to createRecurringBotRunsForSchedule but is much simpler.

  • It's designed for schedules where is_recurring is false.
  • It deletes all existing runs for that schedule_id.
  • It creates exactly one bot_run record based on the schedule.start_datetimez.
  • Note: This function is not currently called by the /api/bot-runs route.

expandAndUpsertRuns

This function is present but not called by the API route. It represents an alternative (and likely more robust) strategy for creating runs.

  • It also calculates a window (windowStart, windowEnd).
  • It also gets base events from the RRule.
  • Key Difference: Instead of deleting and re-inserting runs in the application code, it passes the list of calculated event times (p_base_events) to a Supabase RPC named schedule_expand_and_upsert.
  • This database function is likely responsible for handling the "upsert" logic, (e.g., "insert this run if it doesn't exist"), which can be more efficient and safer from race conditions than the "delete-then-insert" pattern.

Data-Fetching and Ad-Hoc Creation

  • getBotRunsForBot / getBotRunsForMultipleBots: These are standard data-fetching functions used by the application frontend to display lists and details of past and scheduled bot runs, with support for filtering and pagination.
  • createSingleBotRun: This function is used to create a single, ad-hoc bot run that is not associated with a schedule (schedule_id: null). This is likely used for a "Run Now" button in the UI.