Outage Recovery

Handles end-to-end outage recovery for a service address. Validates the outage report, enforces a cooling-off Wait for grid stabilization, runs concurrent meter-status and anomaly checks in a Parallel state, then restores service and notifies the customer or fails with a structured error.
{
  "Comment": "Outage recovery: validates the outage report, enforces a cooling-off Wait for grid stabilization, runs concurrent meter-status and anomaly checks in a Parallel state, then restores service and notifies the customer or fails with a structured error.",
  "StartAt": "SetOutageDefaults",
  "States": {
    "SetOutageDefaults": {
      "Type": "Pass",
      "Parameters": {
        "meterId.$": "$.meterId",
        "accountId.$": "$.accountId",
        "serviceAddress.$": "$.serviceAddress",
        "outageId.$": "$.outageId",
        "reportedAt.$": "$.reportedAt",
        "reportedBy.$": "$.reportedBy",
        "outageType.$": "$.outageType",
        "currentReading.$": "$.currentReading",
        "previousReading.$": "$.previousReading",
        "readingDate.$": "$.readingDate",
        "unit.$": "$.unit",
        "recoveryStatus": "IN_PROGRESS"
      },
      "Next": "ValidateOutageReport"
    },
    "ValidateOutageReport": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": {
        "FunctionName": "${ValidateMeterReadingFunctionArn}",
        "Payload.$": "$"
      },
      "ResultPath": "$.validation",
      "Retry": [
        {
          "ErrorEquals": [
            "Lambda.ServiceException",
            "Lambda.AWSLambdaException",
            "Lambda.SdkClientException"
          ],
          "IntervalSeconds": 2,
          "MaxAttempts": 2,
          "BackoffRate": 2
        }
      ],
      "Catch": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "ResultPath": "$.error",
          "Next": "RecoveryFailed"
        }
      ],
      "Next": "IsOutageReportValid"
    },
    "IsOutageReportValid": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.validation.Payload.isValid",
          "BooleanEquals": true,
          "Next": "GridStabilizationWait"
        }
      ],
      "Default": "RecoveryFailed"
    },
    "GridStabilizationWait": {
      "Type": "Wait",
      "Comment": "Wait for grid voltage and frequency to stabilize before checking meter status.",
      "Seconds": 3,
      "Next": "RecoveryClearance"
    },
    "RecoveryClearance": {
      "Type": "Parallel",
      "Comment": "Confirm meter is back online and usage is within normal range before restoring service.",
      "Branches": [
        {
          "StartAt": "PostOutageMeterCheck",
          "States": {
            "PostOutageMeterCheck": {
              "Type": "Task",
              "Resource": "arn:aws:states:::lambda:invoke",
              "Parameters": {
                "FunctionName": "${CheckMeterStatusFunctionArn}",
                "Payload.$": "$"
              },
              "End": true
            }
          }
        },
        {
          "StartAt": "PostOutageAnomalyCheck",
          "States": {
            "PostOutageAnomalyCheck": {
              "Type": "Task",
              "Resource": "arn:aws:states:::lambda:invoke",
              "Parameters": {
                "FunctionName": "${DetectAnomalyFunctionArn}",
                "Payload.$": "$"
              },
              "End": true
            }
          }
        }
      ],
      "ResultPath": "$.clearance",
      "Catch": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "ResultPath": "$.error",
          "Next": "RecoveryFailed"
        }
      ],
      "Next": "IsGridClear"
    },
    "IsGridClear": {
      "Type": "Choice",
      "Choices": [
        {
          "And": [
            {
              "Variable": "$.clearance[0].Payload.online",
              "BooleanEquals": true
            },
            {
              "Variable": "$.clearance[0].Payload.tamperDetected",
              "BooleanEquals": false
            }
          ],
          "Next": "NotifyOutageRestored"
        }
      ],
      "Default": "RecoveryFailed"
    },
    "NotifyOutageRestored": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": {
        "FunctionName": "${NotifyCustomerFunctionArn}",
        "Payload": {
          "notificationType": "OUTAGE_RESTORED",
          "reading.$": "$"
        }
      },
      "ResultPath": "$.notification",
      "Retry": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "IntervalSeconds": 2,
          "MaxAttempts": 3,
          "BackoffRate": 2
        }
      ],
      "Catch": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "ResultPath": "$.error",
          "Next": "RecoveryFailed"
        }
      ],
      "Next": "RecoveryComplete"
    },
    "RecoveryComplete": {
      "Type": "Succeed"
    },
    "RecoveryFailed": {
      "Type": "Fail",
      "Error": "RecoveryError",
      "Cause": "Outage recovery could not be completed — meter offline, tamper detected, or upstream error"
    }
  }
}
JSON
Expand
100%

Energy teams can use patterns like this to build reliable, compliant, and scalable automation for payment systems and can test and refine these flows locally with Thrubit to reduce cloud cost and speed up iteration.

Free Trial