Skip to content

feat: Add Restart Processing + fix Teams link-unfurling cancel/restart loop#103

Closed
yaqi-lyu wants to merge 6 commits intomasterfrom
restart-process
Closed

feat: Add Restart Processing + fix Teams link-unfurling cancel/restart loop#103
yaqi-lyu wants to merge 6 commits intomasterfrom
restart-process

Conversation

@yaqi-lyu
Copy link
Copy Markdown
Member

@yaqi-lyu yaqi-lyu commented May 6, 2026

Summary

This branch adds a Restart Processing capability and fixes a critical bug where Teams' link-unfurling (URL prefetch) was causing an infinite cancel → restart → cancel loop.


Bug Fix: Teams Link Unfurling Loop

Root Cause

Teams automatically sends GET requests to URLs in notification cards for link-preview generation. Since CancelProcessing and RestartProcessing both accepted GET requests and executed their actions immediately, this caused:

"started" notification with cancelUrl → Teams prefetches cancelUrl (GET) → auto-cancel
"cancelled" notification with restartUrl → Teams prefetches restartUrl (GET) → auto-restart
→ infinite loop

This was only triggered after the restartUrl was added to "cancelled" notifications (the new feature in this branch), which closed the loop.

Fix

  • GET → returns a confirmation page (no action taken, safe for Teams prefetch)
  • POST → executes the actual cancel/restart

For RestartProcessing GET, checks in-memory cache first:

  • If already running → shows "Already Running" page immediately (no confirmation step needed)
  • If not running → shows confirmation page

New Feature: Restart Processing

Adds RestartProcessing.js — an HTTP endpoint that re-queues a transcript for processing after cancellation or failure.

Concurrency protection (3 layers):

  1. In-memory cache check (GET, instant) — shows "Already Running" if same-instance cache has a live execution
  2. Container Apps API live check (POST) — full API scan before queueing, catches cross-instance cases
  3. Queue-level dedup (restartId) — prevents Azure Queue redelivery from firing twice

Changes

New files

  • azure-function/src/functions/RestartProcessing.js — HTTP trigger for restart
  • azure-function/src/htmlResponseCard.js — shared HTML response card + new renderConfirmationCard

Modified files

CancelProcessing.js

  • GET → confirmation page (breaks Teams unfurl loop)
  • POST → cancel action (existing logic, now with security hardening)
  • Infrastructure IDs (subscriptionId, resourceGroup, jobName) read server-side from env vars, not from URL params
  • Cancel success page: removed Restart button (users restart via Teams notification)
  • Added buildRestartUrl helper to pass restart URL to notifications

ProcessTranscriptQueue.js

  • Added findActiveExecutionForMeeting() — lets RestartProcessing check if a job is already running for a meeting
  • Added restartTrigger / restartId dedup path — restart messages use per-click unique ID to prevent Azure Queue redelivery, while still allowing multiple legitimate restarts

entrypoint.sh

  • Cancel checker background process polls every 15s; on cancellation signals parent process group
  • on_sigterm checks CheckCancellation endpoint before sending cancelled notification (avoids mislabelling platform shutdowns as user cancels)
  • exit 0 on confirmed user cancel so Container Apps Job status = Succeeded (not Failed), keeping Stopped/Failed/Succeeded states semantically distinct

sendNotification.js

  • Passes restartUrl in "cancelled" and "failed" notifications
  • Passes cancelUrl in "started" notifications

@yaqi-lyu yaqi-lyu closed this May 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant