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

未关闭
#292 1 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看
主要语言
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

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。