Skip to content

Commit 44984a3

Browse files
committed
Improves SSE diagnostics; addresses Azure buffering
Introduces a new diagnostic page for real-time event testing Enhances SSE logging to support detailed troubleshooting Provides guidance on mitigating buffering behind Azure proxies
1 parent 848ed4c commit 44984a3

File tree

3 files changed

+431
-2
lines changed

3 files changed

+431
-2
lines changed

SSE_AZURE_FRONTDOOR_FIX.md

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
# SSE Azure Front Door Fix
2+
3+
**Issue:** Events stored in Table Storage immediately but take minutes to appear in UI even after SSE fix deployed.
4+
5+
## Root Cause
6+
7+
Azure Front Door (or Azure App Service ARR proxy) is still buffering SSE responses despite the `X-Accel-Buffering: no` header.
8+
9+
## Diagnosis Steps
10+
11+
### 1. Test SSE Connection Directly
12+
13+
Use the diagnostic tool:
14+
```
15+
https://app-scripting-editor.trackmangolfdev.com/sse-test.html
16+
```
17+
18+
**Steps:**
19+
1. Enter a webhook path (e.g., `test-debug`)
20+
2. Click "Connect SSE"
21+
3. Click "Send Test Event"
22+
4. Check if event appears immediately in the log
23+
24+
**Expected:** Event appears within 1 second
25+
**Actual:** Event delayed by minutes → Front Door buffering issue
26+
27+
### 2. Check Browser Network Tab
28+
29+
**F12 → Network → Filter by `stream`:**
30+
- Look for `/api/webhook/{path}/stream` request
31+
- Check if connection stays open
32+
- Check response headers for `X-Accel-Buffering: no`
33+
- Check if data arrives in chunks or buffered
34+
35+
### 3. Direct App Service Test (Bypass Front Door)
36+
37+
Get App Service direct URL:
38+
```bash
39+
az webapp show --name tps-app-scripting-editor --resource-group tps-app-scripting-rg --query defaultHostName -o tsv
40+
```
41+
42+
Test SSE directly:
43+
```bash
44+
# Replace {app-service-url} with output from above
45+
curl -N https://{app-service-url}/api/webhook/test/stream
46+
```
47+
48+
**If this works immediately:** Front Door is the problem
49+
**If this is also slow:** App Service proxy issue
50+
51+
## Solutions
52+
53+
### Solution 1: Azure Front Door Rule for SSE (Recommended)
54+
55+
Azure Front Door needs a routing rule to disable buffering for SSE endpoints.
56+
57+
**Azure Portal:**
58+
1. Go to Front Door profile
59+
2. **Endpoint manager** → Select your endpoint
60+
3. **Origin groups** → Configure origin
61+
4. **Rules** → Add rule:
62+
```
63+
Name: SSE-No-Buffer
64+
Conditions:
65+
- URL path: Matches → /api/webhook/*/stream
66+
Actions:
67+
- Route configuration → Caching → Disabled
68+
- Response headers → Add header:
69+
X-Accel-Buffering: no
70+
```
71+
72+
**Azure CLI:**
73+
```bash
74+
# Get Front Door profile name
75+
az afd profile list --resource-group tps-app-scripting-rg
76+
77+
# Add rule to disable caching for SSE
78+
az afd rule create \
79+
--resource-group tps-app-scripting-rg \
80+
--profile-name <your-front-door-profile> \
81+
--rule-set-name DefaultRuleSet \
82+
--rule-name SSENoBuffer \
83+
--order 1 \
84+
--match-variable UrlPath \
85+
--operator Contains \
86+
--match-values "/stream" \
87+
--action-name DisableCaching \
88+
--enable-caching false
89+
```
90+
91+
### Solution 2: App Service Configuration
92+
93+
Ensure App Service is not buffering either:
94+
95+
```bash
96+
az webapp config set \
97+
--name tps-app-scripting-editor \
98+
--resource-group tps-app-scripting-rg \
99+
--http20-enabled true \
100+
--web-sockets-enabled true
101+
```
102+
103+
Add Application Setting:
104+
```bash
105+
az webapp config appsettings set \
106+
--name tps-app-scripting-editor \
107+
--resource-group tps-app-scripting-rg \
108+
--settings \
109+
ASPNETCORE_HTTP2_ENABLE_GRACEFULSHUTDOWN=true \
110+
WEBSITE_DISABLE_OVERLAPPED_RECYCLING=true
111+
```
112+
113+
### Solution 3: Alternative - WebSockets Fallback
114+
115+
If SSE continues to have issues, implement WebSocket fallback:
116+
117+
**server/src/webhook.ts:**
118+
```typescript
119+
import { WebSocketServer } from 'ws';
120+
121+
// Add WebSocket server alongside SSE
122+
const wss = new WebSocketServer({ noServer: true });
123+
124+
server.on('upgrade', (request, socket, head) => {
125+
if (request.url?.startsWith('/api/webhook/') && request.url?.endsWith('/stream-ws')) {
126+
wss.handleUpgrade(request, socket, head, (ws) => {
127+
const pathMatch = request.url.match(/\/api\/webhook\/([^/]+)\/stream-ws/);
128+
if (!pathMatch) return ws.close();
129+
130+
const userPath = pathMatch[1];
131+
// Store WS client similar to SSE
132+
// Broadcast events via ws.send()
133+
});
134+
}
135+
});
136+
```
137+
138+
**Frontend (WebhookInspector.tsx):**
139+
```typescript
140+
// Try WebSocket if EventSource fails repeatedly
141+
const ws = new WebSocket(`wss://${window.location.host}/api/webhook/${userPath}/stream-ws`);
142+
ws.onmessage = (event) => {
143+
const data = JSON.parse(event.data);
144+
// Handle same as SSE
145+
};
146+
```
147+
148+
### Solution 4: Polling Fallback (Last Resort)
149+
150+
If real-time updates continue to fail, add polling:
151+
152+
```typescript
153+
// Poll every 5 seconds when SSE disconnected
154+
React.useEffect(() => {
155+
if (connected) return; // Don't poll if SSE connected
156+
157+
const interval = setInterval(async () => {
158+
const r = await fetch(`/api/webhook/${userPath}/events?limit=10`);
159+
const j = await r.json();
160+
// Merge new events into existing
161+
}, 5000);
162+
163+
return () => clearInterval(interval);
164+
}, [connected, userPath]);
165+
```
166+
167+
## Verification
168+
169+
After implementing Solution 1 or 2:
170+
171+
1. **Wait for Front Door rule propagation** (~15 minutes)
172+
2. **Test with diagnostic tool:**
173+
```
174+
https://app-scripting-editor.trackmangolfdev.com/sse-test.html
175+
```
176+
3. **Send test event and verify it appears within 1 second**
177+
4. **Check browser console for SSE logs**
178+
179+
## Current Status
180+
181+
✅ Backend SSE fixes deployed (X-Accel-Buffering, keepalive, flush)
182+
✅ Table Storage working (events appear immediately)
183+
❌ Front Door/Proxy still buffering SSE responses
184+
❌ Need to configure Front Door routing rule
185+
186+
## Next Steps
187+
188+
1. **Identify Front Door profile** - Check Azure Portal or ask DevOps
189+
2. **Add SSE routing rule** - Disable caching for `/stream` endpoints
190+
3. **Test with diagnostic tool** - Verify events appear immediately
191+
4. **If still fails** - Consider WebSocket fallback
192+
193+
## Additional Debugging
194+
195+
### Check App Service Logs
196+
197+
```bash
198+
az webapp log tail \
199+
--name tps-app-scripting-editor \
200+
--resource-group tps-app-scripting-rg
201+
```
202+
203+
Look for:
204+
```
205+
SSE connected: path=<path> remote=<ip> clients=1
206+
[webhook] minimal SSE sent path=<path> eventId=<id> elapsedMs=5
207+
```
208+
209+
If you see these logs but UI doesn't update → **Definitely Front Door buffering**
210+
211+
### Check Front Door Logs
212+
213+
```bash
214+
az monitor diagnostic-settings list \
215+
--resource /subscriptions/{sub}/resourceGroups/tps-app-scripting-rg/providers/Microsoft.Cdn/profiles/{profile}
216+
```
217+
218+
Look for buffering or caching behavior on `/stream` URLs.
219+
220+
## References
221+
222+
- [Azure Front Door routing rules](https://docs.microsoft.com/en-us/azure/frontdoor/front-door-rules-engine)
223+
- [Server-Sent Events spec](https://html.spec.whatwg.org/multipage/server-sent-events.html)
224+
- [Azure App Service WebSocket support](https://docs.microsoft.com/en-us/azure/app-service/configure-common)

0 commit comments

Comments
 (0)