# Recurring Schedule & Drift Monitoring

> This report lists all currently queued recurring batch processes from the PeopleSoft Process Scheduler and acts as the source for schedule drift mo...

---

Site [llms.txt](/llms.txt)

---

<div class="alert alert-primary border shadow-sm mb-4 psl-prospect-cta" role="note">
  <div class="d-flex flex-column flex-lg-row align-items-lg-center justify-content-between gap-3">
    <div>
      <strong>New to psLens?</strong> This page documents one specific report. To see how it runs in the product, what
      the output looks like, and how teams use it in practice, start with a live walkthrough.
    </div>
    <div class="d-flex flex-wrap gap-2">
      <a class="btn btn-sm btn-primary" href="/contact/">Book a Demo</a>
      <a class="btn btn-sm btn-outline-primary" href="/docs/reports/">Browse Reports</a>
    </div>
  </div>
</div><div id="pslens-context-panel" class="card border-info mb-4 d-none">
  <div class="card-header bg-light text-info py-2 fw-bold d-flex align-items-center border-bottom border-info-subtle">
    <i class="bi bi-info-circle-fill me-2"></i>
    <span>Tailored Operational Context</span>
  </div>
  <div class="card-body p-0">
    <ul class="list-group list-group-flush">
      <li id="row-db" class="list-group-item d-flex align-items-center justify-content-between py-2 d-none">
        <strong>Target Database:</strong>
        <span id="ctx-db" class="badge bg-secondary font-monospace">&mdash;</span>
      </li>
      <li id="row-type" class="list-group-item d-flex align-items-center justify-content-between py-2 d-none">
        <strong>Context Type:</strong>
        <span id="ctx-type" class="badge bg-light text-dark border font-monospace text-uppercase">&mdash;</span>
      </li>
      <li id="row-severity" class="list-group-item d-flex align-items-center justify-content-between py-2 d-none">
        <strong>Alert Severity:</strong>
        <span id="ctx-severity" class="badge">&mdash;</span>
      </li>
      <li id="row-time" class="list-group-item d-flex align-items-center justify-content-between py-2 d-none">
        <strong>Triggered Time:</strong>
        <span id="ctx-time" class="text-muted small">&mdash;</span>
      </li>
      <li id="row-details" class="list-group-item py-2 d-none">
        <strong id="label-details" class="d-block mb-1">Firing Context:</strong>
        <code id="ctx-details" class="d-block p-2 bg-light border rounded small"
          style="white-space: pre-wrap; word-break: break-all;">&mdash;</code>
      </li>
      <li id="row-sql" class="list-group-item py-2 d-none">
        <div class="d-flex justify-content-between align-items-center mb-1">
          <strong id="label-sql">Contextual SQL:</strong>
          <button id="btn-copy-sql" type="button" class="btn btn-sm btn-outline-secondary py-0 px-2 small">
            <i class="bi bi-clipboard me-1"></i>Copy SQL
          </button>
        </div>
        <pre class="mb-0 p-2 bg-light border rounded small"><code id="ctx-sql" style="white-space: pre-wrap; word-break: break-word;">&mdash;</code></pre>
      </li>
    </ul>
  </div>
</div>

<script>
  (function () {
    const params = new URLSearchParams(window.location.search);
    const metadata = params.get('metadata');
    if (!metadata) return;

    try {
      
      const base64 = metadata.replace(/-/g, '+').replace(/_/g, '/');
      const jsonStr = decodeURIComponent(escape(window.atob(base64)));
      const data = JSON.parse(jsonStr);

      if (data) {
        let hasData = false;

        if (data.db) {
          document.getElementById('ctx-db').textContent = data.db;
          document.getElementById('row-db').classList.remove('d-none');
          hasData = true;
        }

        if (data.type) {
          document.getElementById('ctx-type').textContent = data.type;
          document.getElementById('row-type').classList.remove('d-none');
          hasData = true;
        }

        if (data.severity) {
          const severityBadge = document.getElementById('ctx-severity');
          const severity = data.severity.toLowerCase();
          severityBadge.textContent = severity.toUpperCase();
          if (severity === 'critical') {
            severityBadge.className = 'badge bg-danger';
          } else if (severity === 'warning') {
            severityBadge.className = 'badge bg-warning text-dark';
          } else {
            severityBadge.className = 'badge bg-info';
          }
          document.getElementById('row-severity').classList.remove('d-none');
          hasData = true;
        }

        if (data.t) {
          const date = new Date(data.t * 1000);
          document.getElementById('ctx-time').textContent = date.toLocaleString();
          document.getElementById('row-time').classList.remove('d-none');
          hasData = true;
        }

        if (data.details) {
          document.getElementById('ctx-details').textContent = data.details;

          
          const labelDetails = document.getElementById('label-details');
          if (data.type === 'object') {
            labelDetails.textContent = 'Object Metadata Details:';
          } else if (data.type === 'report') {
            labelDetails.textContent = 'Report Description:';
          } else {
            labelDetails.textContent = 'Firing Context:';
          }

          document.getElementById('row-details').classList.remove('d-none');
          hasData = true;
        }

        if (data.sql) {
          document.getElementById('ctx-sql').textContent = data.sql;
          document.getElementById('row-sql').classList.remove('d-none');
          const copyBtn = document.getElementById('btn-copy-sql');
          if (copyBtn && navigator.clipboard) {
            copyBtn.addEventListener('click', function () {
              navigator.clipboard.writeText(data.sql).then(function () {
                copyBtn.innerHTML = '<i class="bi bi-check2 me-1"></i>Copied';
                setTimeout(function () {
                  copyBtn.innerHTML = '<i class="bi bi-clipboard me-1"></i>Copy SQL';
                }, 2000);
              });
            });
          }
          hasData = true;
        }

        if (hasData) {
          document.getElementById('pslens-context-panel').classList.remove('d-none');
        }
      }
    } catch (e) {
      console.error('Failed to parse operational context metadata:', e);
    }
  })();
</script>

## Recurring Schedule & Drift Monitoring Report

**Report ID:** `recurring-processes`
**Category:** Process Scheduler

## Purpose

This report lists all currently queued recurring batch processes from the PeopleSoft Process Scheduler and acts as the source for schedule drift monitoring. When scheduled with the **On Change** (`on_change`) notification mode, it automatically alerts on changes (added, removed, or server assignment changes) compared to a baseline run.

It captures the batch schedule configuration so it can be preserved for disaster recovery, environment migrations, or operational documentation.

The report answers: "What recurring processes are currently scheduled, who set them up, with what run control, on what recurrence, and on which server?"

## What It Captures

For each queued process with a recurrence assigned:

- **OPRID**. The operator who scheduled the process
- **RUNCNTLID**. The run control ID used
- **RECURNAME**. The recurrence definition controlling the schedule
- **SERVERNAMERUN**. The Process Scheduler server assigned to run it
- **Process Name and Type**. The process definition being executed

Additionally, the report fetches and displays the schedule details for each unique recurrence found (type, days, time window, repeat interval).

## Tables Queried

### PSPRCSRQST — Process Request Instances

The primary table for process scheduler requests.

|     Field     |            Description             |         Filter         |
| ------------- | ---------------------------------- | ---------------------- |
| PRCSINSTANCE  | Unique process instance number     |                        |
| PRCSNAME      | Process definition name            |                        |
| PRCSTYPE      | Process type (SQR, AE, COBOL, etc) |                        |
| OPRID         | Operator who scheduled the process |                        |
| RUNCNTLID     | Run control ID                     |                        |
| RUNSTATUS     | Current run status                 | Filtered to 5 (Queued) |
| SERVERNAMERUN | Assigned server                    |                        |
| RECURNAME     | Recurrence name                    | Filtered to non-blank  |
| RUNDTTM       | Scheduled run date/time            |                        |

### PRCSRECUR — Recurrence Definitions

Looked up for each unique recurrence found to display schedule details.

|      Field       |                 Description                  |
| ---------------- | -------------------------------------------- |
| RECURNAME        | Recurrence name (primary key)                |
| RECURDESCR       | Description                                  |
| RECURTYPE        | Type: 2=Daily, 4=Weekly, 6=Monthly, 8=Custom |
| RUN{DAY} flags   | Which days of the week to run                |
| BEGINDTTM        | Schedule start date/time                     |
| ENDDTTM          | Schedule end date/time                       |
| REPEATRECURRENCE | Repeat interval value                        |
| REPEATUNIT       | Repeat unit: 0=Minutes, 1=Hours              |

## Data Flow

```text
1. Query PSPRCSRQST where RECURNAME <> ' ' AND RUNSTATUS = 5
   Paginate through all results (batches of 300)
        |
        v
2. Collect unique RECURNAME values
   For each, fetch PRCSRECUR via GetRecurrenceByName
        |
        v
3. Generate Markdown report:
   - Summary counts
   - Main table of all queued recurring processes
   - Recurrence schedule details section
```

## Report Output

The generated report contains:

- **Header** with database name and generation timestamp
- **Summary** with total process count, unique recurrences, unique operators, unique servers
- **Process Table** with Process Name, Type, OPRID, Run Control ID, Recurrence, Server, Run Date/Time
- **Recurrence Details** for each unique recurrence: type, scheduled days, start/end dates, repeat interval, duration

## Parameters

This report has no configurable parameters.

## Interpreting Results

- Each row represents a process request that is currently queued with a recurring schedule
- The same process may appear multiple times if scheduled by different operators or with different run controls
- If a server column shows "(any)", the process can run on any available Process Scheduler server
- The Recurrence Details section shows how often each schedule runs

## Use Cases

1. **Disaster Recovery**. Document the batch schedule before a system outage so it can be recreated
2. **Environment Migration**. Capture batch schedules before refreshing or migrating an environment
3. **Audit**. Review who has scheduled recurring processes and on which servers
4. **Operational Documentation**. Maintain a record of the production batch schedule
