# Stalled Recurrences

LLMS index: [llms.txt](/llms.txt)

---

<div class="alert alert-primary border shadow-sm mb-4" 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>
    </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 (hasData) {
          document.getElementById('pslens-context-panel').classList.remove('d-none');
        }
      }
    } catch (e) {
      console.error('Failed to parse operational context metadata:', e);
    }
  })();
</script>

## Stalled Recurrences Report

**Report ID:** `stalled-recurrences`
**Category:** Process Scheduler

## Purpose

This report identifies scheduled recurring processes that have completed a run recently but do not have a subsequent scheduled instance.

In PeopleSoft, recurring batch schedules are kept active by the Process Scheduler, which automatically schedules the next run when the current run starts or completes. However, issues like database refreshes, scheduler outages, cancellations, or errors can cause a schedule to stall without generating a future instance. This report lists all such stalled recurring processes to ensure they can be resumed.

The report answers: "Which of my recurring batch processes have stopped scheduling?"

## Parameters

|    Parameter    | Default |                                                               Description                                                               |
| --------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `lookback_days` | `14`    | The window in days. The report checks for recurring processes that completed their last run within this window but have no future runs. |

## Tables Queried

### PSPRCSRQST — Process Request Instances

The report queries `PSPRCSRQST` to fetch historical and future instances that have a recurrence name assigned:

```sql
SELECT PRCSINSTANCE, PRCSNAME, RUNCNTLID, OPRID, RECURNAME, RUNSTATUS, BEGINDTTM, ENDDTTM, RUNDTTM
FROM PSPRCSRQST
WHERE RECURNAME <> ' '
  AND COALESCE(BEGINDTTM, RUNDTTM) >= TO_DATE('{cutoff}', 'YYYY-MM-DD')
```

## Data Flow

```text
1. Calculate the lookback cutoff date based on 'lookback_days'
        |
        v
2. Query PSPRCSRQST for all requests with a recurrence name since the cutoff date
        |
        v
3. Group requests by (PRCSNAME, RUNCNTLID, OPRID, RECURNAME)
        |
        v
4. For each group:
   - Identify active/pending instances (Queued, Blocked, Hold, Pending, Initiated, Processing, Posting, Restart)
   - Identify completed instances (Success, Error, Cancelled, etc.)
   - If there is at least one completed run, but ZERO active/pending runs:
     - Mark the recurrence as stalled
     - Find the latest completed instance
        |
        v
5. Generate the Markdown report:
   - Summary count of stalled recurrences
   - Table of stalled recurrences with last run status and links
   - Troubleshooting recommendations
```

## Report Output

The generated report contains:

- **Header** displaying the database name, run ID, and lookback window.
- **Summary** showing the count of stalled recurrences detected.
- **Results Table** with columns: Process Name, Recurrence, User, Run Control, Last Instance, Last Status, and Last Run Date/Time.
- **Recommendations** detailing the resolution steps.

## Interpreting Results

If a recurrence is listed in the report, it has stopped running. Check the **Last Status** column:

- **Error / Not Successful / Unable to Post**: The schedule stopped due to a process failure. The scheduler may not have been able to queue the next run, or the recurrence was stopped.
- **Success / Success with Warning / Cancelled**: The process ran or was cancelled but did not reschedule. This could happen if the recurrence ended naturally (reached its end date), or if it was manually cancelled and not rescheduled.
