एक्सपो + सुपाबेस कोल्ड-स्टार्ट सुरक्षित आर्किटेक्चर

Wikiprompt से, मुफ्त प्रॉम्प्ट विश्वकोश

Tugrul Erdem
योगदानकर्ताTugrul Erdemस्रोत

25 दिस॰ 2025

एक्सपो + सुपाबेस कोल्ड-स्टार्ट सुरक्षित आर्किटेक्चर एक्सपो, सुपाबेस, और एआई जनरेशन के लिए एक अलग वर्कर सेवा का उपयोग करके एक स्केलेबल, कोल्ड-स्टार्ट-सुरक्षित मोबाइल ऐप आर्किटेक्चर डिजाइन करने के लिए एक व्यापक प्रॉम्प्ट।

प्रॉम्प्ट सामग्रीसहेजें

🌐
A) वास्तुकला सारांश यह आर्किटेक्चर एक "कोल्ड-स्टार्ट सुरक्षित" दृष्टिकोण का उपयोग करता है, जहां क्लाइंट (Expo) कभी भी एज फंक्शन या डेटाबेस के धीमे होने पर ब्लॉक नहीं होता है। एज फंक्शन केवल हल्के गेटिंग (प्रमाणीकरण, क्रेडिट जांच) और जॉब एनक्यू करने के लिए उपयोग होते हैं। भारी AI जनरेशन और स्टोरेज राइट्स एक अलग वर्कर सेवा द्वारा संभाले जाते हैं, जो जॉब्स टेबल को पोल करता है। यह सुनिश्चित करता है कि एज फंक्शन का कोल्ड-स्टार्ट समय उपयोगकर्ता अनुभव को प्रभावित न करे, और असफल जॉब्स भी मूल इनपुट के साथ एक जनरेशन रिकॉर्ड बनाते हैं। B) माइग्रेशन (SQL) ```sql -- jobs table create table public.jobs ( id uuid primary key default gen_random_uuid(), user_id uuid not null references auth.users(id) on delete cascade, status text not null default 'queued' check (status in ('queued', 'processing', 'completed', 'failed')), input_prompt text not null, created_at timestamptz not null default now(), updated_at timestamptz not null default now() ); create index jobs_status_idx on public.jobs (status); create index jobs_user_id_idx on public.jobs (user_id); alter table public.jobs enable row level security; create policy "Users can view own jobs" on public.jobs for select using (auth.uid() = user_id); create policy "Users can insert own jobs" on public.jobs for insert with check (auth.uid() = user_id); create policy "Users can update own jobs" on public.jobs for update using (auth.uid() = user_id); -- generations table create table public.generations ( id uuid primary key default gen_random_uuid(), job_id uuid not null references public.jobs(id) on delete cascade, user_id uuid not null references auth.users(id) on delete cascade, status text not null default 'pending' check (status in ('pending', 'completed', 'failed')), input_prompt text not null, output_url text, error_message text, created_at timestamptz not null default now(), updated_at timestamptz not null default now() ); create index generations_job_id_idx on public.generations (job_id); create index generations_user_id_idx on public.generations (user_id); alter table public.generations enable row level security; create policy "Users can view own generations" on public.generations for select using (auth.uid() = user_id); create policy "Users can insert own generations" on public.generations for insert with check (auth.uid() = user_id); create policy "Users can update own generations" on public.generations for update using (auth.uid() = user_id); -- entitlements table create table public.entitlements ( id uuid primary key default gen_random_uuid(), user_id uuid not null references auth.users(id) on delete cascade, credits_remaining integer not null default 0, is_paid boolean not null default false, updated_at timestamptz not null default now() ); create index entitlements_user_id_idx on public.entitlements (user_id); alter table public.entitlements enable row level security; create policy "Users can view own entitlements" on public.entitlements for select using (auth.uid() = user_id); create policy "Users can update own entitlements" on public.entitlements for update using (auth.uid() = user_id); ``` C) एज फंक्शन फाइल संरचना + मुख्य कोड ब्लॉक ``` supabase/functions/ ping/index.ts enqueue_generation/index.ts get_job_status/index.ts ``` **ping/index.ts** ```typescript import { corsHeaders } from '../_shared/cors.ts'; Deno.serve(async (req) => { if (req.method === 'OPTIONS') { return new Response('ok', { headers: corsHeaders }); } return new Response('pong', { headers: corsHeaders }); }); ``` **enqueue_generation/index.ts** ```typescript import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'; import { corsHeaders } from '../_shared/cors.ts'; Deno.serve(async (req) => { if (req.method === 'OPTIONS') { return new Response('ok', { headers: corsHeaders }); } const supabase = createClient( Deno.env.get('SUPABASE_URL')!, Deno.env.get('SUPABASE_ANON_KEY')! ); const authHeader = req.headers.get('Authorization'); if (!authHeader) { return new Response(JSON.stringify({ error: 'Unauthorized' }), { status: 401, headers: corsHeaders }); } const { data: { user }, error: authError } = await supabase.auth.getUser(authHeader.replace('Bearer ', '')); if (authError || !user) { return new Response(JSON.stringify({ error: 'Unauthorized' }), { status: 401, headers: corsHeaders }); } const { prompt } = await req.json(); if (!prompt || prompt.length < 3) { return new Response(JSON.stringify({ error: 'Invalid prompt' }), { status: 400, headers: corsHeaders }); } // check entitlements const { data: entitlement, error: entError } = await supabase .from('entitlements') .select('credits_remaining, is_paid') .eq('user_id', user.id) .single(); if (entError || !entitlement || (!entitlement.is_paid && entitlement.credits_remaining <= 0)) { return new Response(JSON.stringify({ error: 'Insufficient credits' }), { status: 403, headers: corsHeaders }); } // create job const { data: job, error: jobError } = await supabase .from('jobs') .insert({ user_id: user.id, input_prompt: prompt, status: 'queued' }) .select() .single(); if (jobError) { return new Response(JSON.stringify({ error: 'Failed to create job' }), { status: 500, headers: corsHeaders }); } // decrement credits await supabase .from('entitlements') .update({ credits_remaining: entitlement.credits_remaining - 1 }) .eq('user_id', user.id); return new Response(JSON.stringify({ jobId: job.id }), { status: 200, headers: corsHeaders }); }); ``` **get_job_status/index.ts** ```typescript import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'; import { corsHeaders } from '../_shared/cors.ts'; Deno.serve(async (req) => { if (req.method === 'OPTIONS') { return new Response('ok', { headers: corsHeaders }); } const supabase = createClient( Deno.env.get('SUPABASE_URL')!, Deno.env.get('SUPABASE_ANON_KEY')! ); const authHeader = req.headers.get('Authorization'); if (!authHeader) { return new Response(JSON.stringify({ error: 'Unauthorized' }), { status: 401, headers: corsHeaders }); } const { data: { user }, error: authError } = await supabase.auth.getUser(authHeader.replace('Bearer ', '')); if (authError || !user) { return new Response(JSON.stringify({ error: 'Unauthorized' }), { status: 401, headers: corsHeaders }); } const url = new URL(req.url); const jobId = url.searchParams.get('jobId'); if (!jobId) { return new Response(JSON.stringify({ error: 'Missing jobId' }), { status: 400, headers: corsHeaders }); } const { data: job, error: jobError } = await supabase .from('jobs') .select('status, generations(status, output_url, error_message)') .eq('id', jobId) .eq('user_id', user.id) .single(); if (jobError || !job) { return new Response(JSON.stringify({ error: 'Job not found' }), { status: 404, headers: corsHeaders }); } return new Response(JSON.stringify(job), { status: 200, headers: corsHeaders }); }); ``` D) एक्सपो इंटीग्रेशन नोट्स + मुख्य कोड ब्लॉक **एप स्टार्ट पर नॉन-ब्लॉकिंग वार्म पिंग** ```typescript // lib/warmPing.ts export async function warmPing() { try { await fetch(`${SUPABASE_URL}/functions/v1/ping`, { method: 'GET', headers: { 'Authorization': `Bearer ${anonKey}` } }); } catch (e) { // silently ignore - cold start is fine } } ``` **जेनरेट बटन - ऑप्टिमिस्टिक यूआई + प्लेसहोल्डर** ```typescript // components/GenerateButton.tsx const handleGenerate = async () => { const tempId = `temp-${Date.now()}`; // optimistic UI update setGallery((prev) => [...prev, { id: tempId, status: 'pending', prompt: inputPrompt }]); try { const res = await fetch(`${SUPABASE_URL}/functions/v1/enqueue_generation`, { method: 'POST', headers: { 'Authorization': `Bearer ${session.access_token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ prompt: inputPrompt }) }); if (!res.ok) { throw new Error('Failed to enqueue'); } const { jobId } = await res.json(); // replace temp with real jobId setGallery((prev) => prev.map((item) => item.id === tempId ? { ...item, id: jobId } : item)); subscribeToJob(jobId); } catch (e) { // mark temp as failed setGallery((prev) => prev.map((item) => item.id === tempId ? { ...item, status: 'failed' } : item)); } }; ``` **रियलटाइम सब्सक्रिप्शन + पोलिंग फॉलबैक** ```typescript // lib/jobSubscription.ts export function subscribeToJob(jobId: string) { const channel = supabase .channel(`job-${jobId}`) .on('postgres_changes', { event: 'UPDATE', schema: 'public', table: 'jobs', filter: `id=eq.${jobId}` }, (payload) => { handleJobUpdate(payload.new); }) .subscribe(); // polling fallback after 30s setTimeout(() => { if (!jobCompleted) { pollJobStatus(jobId); } }, 30000); } async function pollJobStatus(jobId: string) { const res = await fetch(`${SUPABASE_URL}/functions/v1/get_job_status?jobId=${jobId}`, { headers: { 'Authorization': `Bearer ${session.access_token}` } }); const data = await res.json(); handleJobUpdate(data); } ``` **फाइनल जनरेशन गैलरी में प्लेसहोल्डर को बदलता है** ```typescript function handleJobUpdate(job: any) { if (job.status === 'completed' && job.generations?.[0]?.output_url) { setGallery((prev) => prev.map((item) => item.id === job.id ? { ...item, status: 'completed', imageUrl: job.generations[0].output_url } : item )); } else if (job.status === 'failed') { setGallery((prev) => prev.map((item) => item.id === job.id ? { ...item, status: 'failed', error: job.generations?.[0]?.error_message } : item )); } } ``` E) वर्कर आउटलाइन + स्यूडो-कोड **वर्कर जिम्मेदारियां:** - क्यू किए गए जॉब्स को फेच करें - AI जनरेशन चलाएं - स्टोरेज में अपलोड करें - जॉब्स अपडेट करें + जनरेशन इंसर्ट करें - रिट्री पॉलिसी और आइडेम्पोटेंसी **वर्कर इंटरफेस (मिनिमल एंडपॉइंट्स):** ``` POST /worker/process-next GET /worker/health ``` **स्यूडो-कोड:** ``` function processNextJob(): job = fetchNextQueuedJob() if job is null: return // idempotency check if job.status != 'queued': return updateJobStatus(job.id, 'processing') try: // run AI generation output = runAIGeneration(job.input_prompt) // upload to storage storagePath = uploadToStorage(job.user_id, output) // update job + insert generation updateJob(job.id, { status: 'completed' }) insertGeneration({ job_id: job.id, user_id: job.user_id, status: 'completed', input_prompt: job.input_prompt, output_url: storagePath }) catch error: // failed job still creates generation record updateJob(job.id, { status: 'failed' }) insertGeneration({ job_id: job.id, user_id: job.user_id, status: 'failed', input_prompt: job.input_prompt, error_message: error.message }) // retry policy - max 3 attempts if job.attempt_count < 3: updateJob(job.id, { status: 'queued', attempt_count: job.attempt_count + 1 }) ``` **रिट्री पॉलिसी:** - अधिकतम 3 प्रयास - प्रत्येक प्रयास के बीच 5 मिनट का बैकऑफ - असफल जनरेशन हमेशा मूल इनपुट के साथ रिकॉर्ड बनाता है **आइडेम्पोटेंसी:** - जॉब आईडी पर आधारित चेक - प्रोसेसिंग से पहले स्टेटस वैलिडेशन - डुप्लीकेट जनरेशन इंसर्ट से बचने के लिए यूनिक कंस्ट्रेंट

पूरा प्रॉम्प्ट देखने के लिए साइन इन करें

Continue with:

By logging in, you agree to our Terms of Use and Privacy Policy

उपयोग

यह प्रॉम्प्ट coding के साथ उपयोग के लिए डिज़ाइन किया गया है। ऊपर प्रॉम्प्ट सामग्री कॉपी करें और अपने पसंदीदा AI टूल में पेस्ट करें।

सर्वोत्तम परिणामों के लिए, आप अपनी विशिष्ट आवश्यकताओं के अनुसार प्लेसहोल्डर (वर्ग कोष्ठक या बड़े अक्षरों में दर्शाए गए) को अनुकूलित कर सकते हैं।

संदर्भ

श्रेणियाँ:coding| prompts.chat| expo| supabase

चर्चा