Skip to content

Runtime Target Lifecycle #2

Runtime Target Lifecycle

Runtime Target Lifecycle #2

name: Runtime Target Lifecycle
on:
workflow_dispatch:
schedule:
- cron: "37 * * * *"
env:
GCP_PROJECT_ID: firstradequant
GCP_WORKLOAD_IDENTITY_PROVIDER: projects/1088907247379/locations/global/workloadIdentityPools/github-actions/providers/github-main
GCP_WORKLOAD_IDENTITY_SERVICE_ACCOUNT: firstrade-platform-deploy@firstradequant.iam.gserviceaccount.com
concurrency:
group: ${{ github.workflow }}-${{ github.ref_name }}
cancel-in-progress: false
jobs:
lifecycle:
name: Publish Firstrade target lifecycle
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
id-token: write
env:
RUNTIME_TARGET_ENABLED: ${{ vars.RUNTIME_TARGET_ENABLED }}
RUNTIME_TARGET_JSON: ${{ secrets.RUNTIME_TARGET_JSON }}
FIRSTRADE_DRY_RUN_ONLY: ${{ vars.FIRSTRADE_DRY_RUN_ONLY }}
CLOUD_RUN_REGION: ${{ vars.CLOUD_RUN_REGION }}
CLOUD_RUN_SERVICE: ${{ secrets.CLOUD_RUN_SERVICE }}
CLOUD_RUN_SERVICES: ${{ secrets.CLOUD_RUN_SERVICES }}
CLOUD_RUN_SERVICE_TARGETS_JSON: ${{ secrets.CLOUD_RUN_SERVICE_TARGETS_JSON }}
RUNTIME_GUARD_LOOKBACK_MINUTES: ${{ vars.RUNTIME_GUARD_LOOKBACK_MINUTES || '180' }}
RUNTIME_GUARD_REQUIRE_SUCCESS: ${{ vars.RUNTIME_GUARD_REQUIRE_SUCCESS || 'false' }}
RUNTIME_HEARTBEAT_GCS_URIS: ${{ vars.RUNTIME_HEARTBEAT_GCS_URIS || vars.EXECUTION_REPORT_GCS_URI }}
RUNTIME_HEARTBEAT_LOOKBACK_HOURS: ${{ vars.RUNTIME_HEARTBEAT_LOOKBACK_HOURS || '36' }}
RUNTIME_HEARTBEAT_ACCEPT_STAGES: ${{ vars.RUNTIME_HEARTBEAT_ACCEPT_STAGES }}
RUNTIME_HEARTBEAT_REJECT_STAGES: ${{ vars.RUNTIME_HEARTBEAT_REJECT_STAGES }}
RUNTIME_HEARTBEAT_MARKET_AWARE: ${{ vars.RUNTIME_HEARTBEAT_MARKET_AWARE || 'true' }}
RUNTIME_HEARTBEAT_MARKET_CALENDAR: ${{ vars.FIRSTRADE_MARKET_CALENDAR }}
RUNTIME_HEARTBEAT_MARKET_TIMEZONE: ${{ vars.FIRSTRADE_MARKET_TIMEZONE }}
RUNTIME_HEARTBEAT_PUBLICATION_GRACE_MINUTES: ${{ vars.RUNTIME_HEARTBEAT_PUBLICATION_GRACE_MINUTES || '30' }}
RUNTIME_HEARTBEAT_SCHEDULER_AWARE: ${{ vars.RUNTIME_HEARTBEAT_SCHEDULER_AWARE || 'true' }}
RUNTIME_HEARTBEAT_SCHEDULER_LOCATION: ${{ vars.RUNTIME_HEARTBEAT_SCHEDULER_LOCATION || vars.CLOUD_RUN_REGION || 'us-central1' }}
EXECUTION_EVIDENCE_SYNC_URL: ${{ vars.EXECUTION_EVIDENCE_SYNC_URL }}
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Resolve declared no-order target state
id: target_state
run: |
set -euo pipefail
python3 - <<'PY' >> "$GITHUB_OUTPUT"
import json
import os
target = {}
raw_target = (os.environ.get("RUNTIME_TARGET_JSON") or "").strip()
if raw_target:
try:
decoded = json.loads(raw_target)
except json.JSONDecodeError as error:
raise SystemExit(f"RUNTIME_TARGET_JSON is invalid: {error}") from error
if isinstance(decoded, dict):
target = decoded
enabled = (os.environ.get("RUNTIME_TARGET_ENABLED") or target.get("runtime_target_enabled") or target.get("RUNTIME_TARGET_ENABLED") or "true").strip().lower()
if enabled not in {"true", "false"}:
raise SystemExit("RUNTIME_TARGET_ENABLED must be true or false")
mode = str(target.get("execution_mode") or "").strip()
if mode not in {"dry_run", "paper", "live"}:
mode = "dry_run" if (os.environ.get("FIRSTRADE_DRY_RUN_ONLY") or "").strip().lower() == "true" else "live"
print(f"configured_state={'enabled' if enabled == 'true' else 'disabled'}")
print(f"execution_mode={mode}")
PY
- name: Authenticate to Google Cloud
uses: google-github-actions/auth@v3
with:
workload_identity_provider: ${{ env.GCP_WORKLOAD_IDENTITY_PROVIDER }}
service_account: ${{ env.GCP_WORKLOAD_IDENTITY_SERVICE_ACCOUNT }}
- name: Set up gcloud
uses: google-github-actions/setup-gcloud@v3
with:
project_id: ${{ env.GCP_PROJECT_ID }}
- name: Check Cloud Run runtime without notification side effects
id: runtime_guard
env:
RUNTIME_GUARD_NAME: FirstradePlatform lifecycle
RUNTIME_GUARD_FAIL_WORKFLOW_ON_ALERT: "true"
run: |
set -uo pipefail
set +e
python scripts/cloud_run_runtime_guard.py > runtime-guard.log 2>&1
exit_code=$?
set -e
cat runtime-guard.log
if [ "$exit_code" -eq 0 ]; then
status=pass
elif grep -Eqi 'log query failed|internal error|network|timed out|unable to list' runtime-guard.log; then
status=unavailable
else
status=attention
fi
echo "status=$status" >> "$GITHUB_OUTPUT"
exit 0
- name: Install market calendar for enabled heartbeat
if: ${{ steps.target_state.outputs.configured_state == 'enabled' }}
run: >-
python -m pip install --disable-pip-version-check
--retries 3 --timeout 30 "pandas-market-calendars==5.4.0"
- name: Check enabled execution heartbeat without notification side effects
id: execution_heartbeat
env:
RUNTIME_HEARTBEAT_NAME: FirstradePlatform lifecycle
RUNTIME_HEARTBEAT_REQUIRED_SERVICES: ${{ secrets.CLOUD_RUN_SERVICE }}
RUNTIME_HEARTBEAT_FAIL_WORKFLOW_ON_ALERT: "true"
run: |
set -uo pipefail
if [ "${{ steps.target_state.outputs.configured_state }}" = "disabled" ]; then
echo "status=not_applicable" >> "$GITHUB_OUTPUT"
echo "Execution heartbeat is not applicable because this target is deliberately disabled."
exit 0
fi
set +e
python scripts/execution_report_heartbeat.py > execution-heartbeat.log 2>&1
exit_code=$?
set -e
cat execution-heartbeat.log
if [ "$exit_code" -eq 0 ] && grep -qi 'heartbeat skipped' execution-heartbeat.log; then
status=not_due
elif [ "$exit_code" -eq 0 ]; then
status=pass
elif grep -Eqi 'gcloud|storage|network|timed out|internal error|unable to list' execution-heartbeat.log; then
status=unavailable
else
status=attention
fi
echo "status=$status" >> "$GITHUB_OUTPUT"
exit 0
- name: Detect unified control-plane ingress
id: lifecycle_ingress
env:
EXECUTION_EVIDENCE_SYNC_TOKEN: ${{ secrets.EXECUTION_EVIDENCE_SYNC_TOKEN }}
run: |
set -euo pipefail
if [ -n "${EXECUTION_EVIDENCE_SYNC_URL:-}" ] && [ -n "${EXECUTION_EVIDENCE_SYNC_TOKEN:-}" ]; then
echo "enabled=true" >> "$GITHUB_OUTPUT"
else
echo "enabled=false" >> "$GITHUB_OUTPUT"
fi
- name: Publish lifecycle to the unified control plane
if: ${{ steps.lifecycle_ingress.outputs.enabled == 'true' }}
uses: QuantStrategyLab/QuantRuntimeSettings/actions/publish-runtime-target-lifecycle@6d71e785dbf21bac6c829a1fc72f3a4492d36f54
with:
source-id: firstrade.primary
target-id: firstrade.primary
platform: firstrade
configured-state: ${{ steps.target_state.outputs.configured_state }}
execution-mode: ${{ steps.target_state.outputs.execution_mode }}
runtime-guard: ${{ steps.runtime_guard.outputs.status }}
execution-heartbeat: ${{ steps.execution_heartbeat.outputs.status }}
sync-url: ${{ env.EXECUTION_EVIDENCE_SYNC_URL }}
env:
EXECUTION_EVIDENCE_SYNC_TOKEN: ${{ secrets.EXECUTION_EVIDENCE_SYNC_TOKEN }}
- name: Explain missing lifecycle ingress configuration
if: ${{ steps.lifecycle_ingress.outputs.enabled != 'true' }}
run: |
echo "Lifecycle was checked but not centrally published: configure EXECUTION_EVIDENCE_SYNC_URL and EXECUTION_EVIDENCE_SYNC_TOKEN." >&2
- name: Summarize no-order lifecycle
run: |
{
echo "## Runtime target lifecycle"
echo
echo "| Field | Value |"
echo "| --- | --- |"
echo "| Target | firstrade.primary |"
echo "| Configured state | ${{ steps.target_state.outputs.configured_state }} |"
echo "| Intended lane | ${{ steps.target_state.outputs.execution_mode }} |"
echo "| Runtime guard | ${{ steps.runtime_guard.outputs.status }} |"
echo "| Execution heartbeat | ${{ steps.execution_heartbeat.outputs.status }} |"
echo
echo "This workflow is read-only: it cannot enable a target, alter its lane, or submit an order."
} >> "$GITHUB_STEP_SUMMARY"