AOSSIE-Org / AOSSIE-Org/Ell-ena
feat: Supabase Edge Functions have no retry mechanism — if `summarize-transcription` or `generate-embeddings` fails due to Gemini API rate limits, the failure is permanent with no user notification
- 主要语言
- Dart
- 星标
- 54
- 派生
- 110
- PR 合并指标
- 30 天内没有已合并 PR
描述
## 🐛 Problem Statement
Ell-ena has 6 Supabase Edge Functions in `supabase/functions/`:
- `fetch-transcript/`
- `generate-embeddings/`
- `search-meetings/`
- `start-bot/`
- `summarize-transcription/`
The AI-dependent functions (`generate-embeddings`, `summarize-transcription`) call the Gemini API. Gemini's free tier enforces rate limits — at peak usage, these calls will receive HTTP 429 (Too Many Requests). Without retry logic, a 429 response causes the Edge Function to fail permanently for that invocation. The meeting transcription is stored, but its embedding and summary are never generated — silently.
The user sees their meeting in the meetings list but gets empty search results and no summary — with no indication that the background processing failed.
## Proposed Fix
Add exponential backoff retry logic inside the affected Edge Functions:
```typescript
// supabase/functions/_shared/retry.ts (new shared utility)
export async function withRetry(
fn: () => Promise,
maxAttempts: number = 3,
baseDelayMs: number = 1000,
): Promise {
let lastError: Error;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
return await fn();
} catch (error: any) {
lastError = error;
// Only retry on rate limit (429) and server errors (5xx)
const isRetryable = error.status === 429 || (error.status >= 500 && error.status < 600);
if (!isRetryable || attempt === maxAttempts) throw error;
// Exponential backoff: 1s, 2s, 4s with ±20% jitter
const delay = baseDelayMs * Math.pow(2, attempt - 1) * (0.8 + Math.random() * 0.4);
console.warn(`Attempt ${attempt} failed (${error.status}). Retrying in ${Math.round(delay)}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw lastError!;
}
```
Apply in `generate-embeddings/index.ts`:
```typescript
import { withRetry } from '../_shared/retry.ts';
const embedding = await withRetry(
() => geminiClient.embedContent({ content: chunk }),
3, // max 3 attempts
1000 // 1s base delay
);
```
Also add a `processing_status` column to the meetings table (`pending | processing | completed | failed`) and update it from the Edge Function, so the Flutter UI can show users when processing has failed and offer a "Retry" button.
## Files to Create/Modify
| File | Change |
|---|---|
| `supabase/functions/_shared/retry.ts` | New shared retry utility |
| `supabase/functions/generate-embeddings/index.ts` | Wrap Gemini calls with `withRetry()` |
| `supabase/functions/summarize-transcription/index.ts` | Wrap Gemini calls with `withRetry()` |
| `supabase/migrations/` | Add `processing_status` column to meetings table |
| `lib/screens/meetings/` | Show processing status and "Retry" button in Flutter UI |
**Suggested labels:** `bug`, `backend`, `reliability`, `level: intermediate`
I would like to work on this. Could you please assign it to me?
贡献指南
这个仓库没有索引到贡献指南
调研方向
Read the existing Edge Functions in supabase/functions/generate-embeddings/index.ts and supabase/functions/summarize-transcription/index.ts, then inspect the meetings migration and lib/screens/meetings/. Trace how Gemini failures and meeting processing currently flow before changing the named areas. Done means retry behavior, processing status updates, and a Flutter retry option are covered across the listed files.
由索引模型根据 Issue 内容生成。
评估
- 技术栈
- dart, flutter, supabase, typescript
- 领域
- backend, database, mobile
- Issue 类型
- 功能
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 活跃度
- 冷清
- 描述清晰度
- 基本清楚
- 新手友好度
- 52/100