توابع لبه Supabase: معرفی وظایف پسزمینه، ذخیرهسازی زودگذر و سوکتهای وب

Summarize this content to 400 words in Persian Lang
ما هیجانزده هستیم که سه ویژگی مورد انتظار را اعلام کنیم: کارهای پسزمینه، ذخیرهسازی فایل زودگذر و WebSockets.
⚡️ اطلاعات بیشتر در هفته راه اندازی
از امروز می توانید از این ویژگی ها در هر پروژه ای استفاده کنید. بیایید کشف کنیم که چه چیزهای هیجان انگیزی می توانید با آنها بسازید.
وظایف پس زمینه
گاهی اوقات برای انجام کارهایی بیشتر از پاسخ به یک درخواست، به یک منطق پشتیبان نیاز دارید. برای مثال، ممکن است بخواهید دسته ای از فایل ها را پردازش کرده و نتایج را در Supabase Storage آپلود کنید. یا چندین ورودی را از یک جدول پایگاه داده بخوانید و برای هر ورودی، جاسازی ایجاد کنید.
با معرفی وظایف پس زمینه، اجرای این بارهای کاری طولانی مدت با توابع Edge بسیار آسان است.
ما یک روش جدید به نام معرفی کرده ایم EdgeRuntime.waitUntil ، که قول می پذیرد. این تضمین میکند که تا زمانی که وعده حل نشود، عملکرد خاتمه نمییابد.
پروژه های رایگان می توانند وظایف پس زمینه را حداکثر برای 150 ثانیه (2 متر 30 ثانیه) اجرا کنند. اگر در طرح پولی هستید، این محدودیت به 400 ثانیه (6 متر و 40 ثانیه) افزایش می یابد. ما قصد داریم در ماه های آینده محدودیت های انعطاف پذیرتری را معرفی کنیم.
هنگامی که عملکرد در شرف خاموش شدن است، می توانید با گوش دادن به اعلان ها مشترک شوید beforeunload رویداد برای جزئیات بیشتر در مورد نحوه استفاده از وظایف پس زمینه، راهنما را بخوانید.
ذخیره سازی زودگذر
فراخوانیهای Edge Function اکنون به ذخیرهسازی زودگذر دسترسی دارند. این برای کارهای پسزمینه مفید است، زیرا به شما امکان میدهد فایلها را بخوانید و بنویسید /tmp دایرکتوری برای ذخیره نتایج میانی
راهنمای نحوه دسترسی به حافظه موقت را بررسی کنید.
مثال: استخراج یک فایل فشرده و آپلود محتوای آن در Supabase Storage
بیایید به یک مثال در دنیای واقعی با استفاده از Background Tasks و Ephemeral Storage نگاه کنیم.
تصور کنید در حال ساخت یک برنامه آلبوم عکس هستید. شما می خواهید که کاربران شما عکس ها را به صورت یک فایل فشرده آپلود کنند. می توانید آنها را در یک تابع Edge استخراج کنید و آنها را در فضای ذخیره سازی آپلود کنید.
یکی از سادهترین راهها برای پیادهسازی استفاده از جریانها است:
import { ZipReaderStream } from ‘https://deno.land/x/zipjs/index.js’
import { createClient } from ‘jsr:@supabase/supabase-js@2’
const supabase = createClient(
Deno.env.get(‘SUPABASE_URL’),
Deno.env.get(‘SUPABASE_SERVICE_ROLE_KEY’)
)
Deno.serve(async (req) => {
const uploadId = crypto.randomUUID()
const { error } = await supabase.storage.createBucket(uploadId, {
public: false,
})
for await (const entry of await req.body.pipeThrough(new ZipReaderStream())) {
// write file to Supabase Storage
const { error } = await supabase.storage
.from(uploadId)
.upload(entry.filename, entry.readable, {})
console.log(‘uploaded’, entry.filename)
}
return new Response(
JSON.stringify({
uploadId,
}),
{
headers: {
‘content-type’: ‘application/json’,
},
}
)
})
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
اگر نسخه استریم را آزمایش کنید، هنگام بارگذاری فایل های فشرده با حجم بالای 100 مگابایت، با خطاهای محدودیت حافظه مواجه می شود. این به این دلیل است که نسخه استریم باید هر فایل را در یک آرشیو فشرده در حافظه نگه دارد.
در عوض میتوانیم آن را تغییر دهیم تا فایل فشرده را در یک فایل موقت بنویسیم. سپس، از یک کار پسزمینه برای استخراج و آپلود آن در Supabase Storage استفاده کنید. به این ترتیب ما فقط قسمت هایی از فایل فشرده را در حافظه می خوانیم.
import { BlobWriter, ZipReader, ZipReaderStream } from ‘https://deno.land/x/zipjs/index.js’
import { createClient } from ‘jsr:@supabase/supabase-js@2’
const supabase = createClient(
Deno.env.get(‘SUPABASE_URL’),
Deno.env.get(‘SUPABASE_SERVICE_ROLE_KEY’)
)
let numFilesUploaded = 0
async function processZipFile(uploadId, filepath) {
const file = await Deno.open(filepath, { read: true })
const zipReader = new ZipReader(file.readable)
const entries = await zipReader.getEntries()
await supabase.storage.createBucket(uploadId, {
public: false,
})
await Promise.all(
entries.map(async (entry) => {
// read file entry
const blobWriter = new BlobWriter()
const blob = await entry.getData(blobWriter)
if (entry.directory) {
return
}
// write file to Supabase Storage
await supabase.storage.from(uploadId).upload(entry.filename, blob, {})
numFilesUploaded += 1
console.log(‘uploaded’, entry.filename)
})
)
await zipReader.close()
}
// you can add a `beforeunload` event listener to be notified
// when Function Worker is about to terminate.
// use this to do any logging, save states.
globalThis.addEventListener(‘beforeunload’, (ev) => {
console.log(‘function about to terminate: ‘, ev.detail.reason)
console.log(‘number of files uploaded: ‘, numFilesUploaded)
})
async function writeZipFile(filepath, stream) {
await Deno.writeFile(filepath, stream)
}
Deno.serve(async (req) => {
const uploadId = crypto.randomUUID()
await writeZipFile(‘/tmp/’ + uploadId, req.body)
// process zip file in a background task
// calling EdgeRuntime.waitUntil() would ensure
// function worker wouldn’t exit until the promise is completed.
EdgeRuntime.waitUntil(processZipFile(uploadId, ‘/tmp/’ + uploadId))
return new Response(
JSON.stringify({
uploadId,
}),
{
headers: {
‘content-type’: ‘application/json’,
},
}
)
})
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
وب سوکت ها
Edge Functions اکنون از ایجاد اتصالات ورودی (سرور) و خروجی (کلینت) WebSocket پشتیبانی می کند. این امکان انواع موارد استفاده جدید را فراهم می کند.
مثال: ساختن یک رله احراز هویت شده برای OpenAI Realtime API
OpenAI اخیرا یک API Realtime را معرفی کرده است که از WebSockets استفاده می کند. اجرای این کار صرفاً در سمت کلاینت دشوار است زیرا باید کلید OpenAI خود را به صورت عمومی در معرض دید قرار دهید. OpenAI ساخت یک سرور برای احراز هویت درخواست ها را توصیه می کند.
با پشتیبانی جدید ما از WebSockets، میتوانید به راحتی این کار را در Edge Functions بدون ایستادن زیرساخت انجام دهید. علاوه بر این، می توانید از Supabase Auth برای احراز هویت کاربران و محافظت از استفاده OpenAI خود در برابر سوء استفاده استفاده کنید.
import { createClient } from ‘jsr:@supabase/supabase-js@2’
const supabase = createClient(
Deno.env.get(‘SUPABASE_URL’),
Deno.env.get(‘SUPABASE_SERVICE_ROLE_KEY’)
)
const OPENAI_API_KEY = Deno.env.get(‘OPENAI_API_KEY’)
Deno.serve(async (req) => {
const upgrade = req.headers.get(‘upgrade’) || ”
if (upgrade.toLowerCase() != ‘websocket’) {
return new Response(“request isn’t trying to upgrade to websocket.”)
}
// WebSocket browser clients does not support sending custom headers.
// We have to use the URL query params to provide user’s JWT.
// Please be aware query params may be logged in some logging systems.
const url = new URL(req.url)
const jwt = url.searchParams.get(‘jwt’)
if (!jwt) {
console.error(‘Auth token not provided’)
return new Response(‘Auth token not provided’, { status: 403 })
}
const { error, data } = await supabase.auth.getUser(jwt)
if (error) {
console.error(error)
return new Response(‘Invalid token provided’, { status: 403 })
}
if (!data.user) {
console.error(‘user is not authenticated’)
return new Response(‘User is not authenticated’, { status: 403 })
}
const { socket, response } = Deno.upgradeWebSocket(req)
socket.onopen = () => {
// initiate an outbound WebSocket connection to OpenAI
const url = ‘wss://api.openai.com/v1/realtime?model=gpt-4o-realtime-preview-2024-10-01’
// openai-insecure-api-key isn’t a problem since this code runs in an Edge Function
const openaiWS = new WebSocket(url, [
‘realtime’,
`openai-insecure-api-key.${OPENAI_API_KEY}`,
‘openai-beta.realtime-v1’,
])
openaiWS.onopen = () => {
console.log(‘Connected to OpenAI server.’)
socket.onmessage = (e) => {
console.log(‘socket message:’, e.data)
// only send the message if openAI ws is open
if (openaiWS.readyState === 1) {
openaiWS.send(e.data)
} else {
socket.send(
JSON.stringify({
type: ‘error’,
msg: ‘openAI connection not ready’,
})
)
}
}
}
openaiWS.onmessage = (e) => {
console.log(e.data)
socket.send(e.data)
}
openaiWS.onerror = (e) => console.log(‘OpenAI error: ‘, e.message)
openaiWS.onclose = (e) => console.log(‘OpenAI session closed’)
}
socket.onerror = (e) => console.log(‘socket errored:’, e.message)
socket.onclose = () => console.log(‘socket closed’)
return response // 101 (Switching Protocols)
})
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
عملکرد و ثبات
در چند ماه گذشته، عملکرد، ثبات و DX بسیاری را در عملکردهای لبه بهبود دادهایم. در حالی که این بهبودها اغلب برای کاربران نهایی قابل مشاهده نیستند، آنها پایه و اساس ویژگی های جدیدی هستند که امروز اعلام می کنیم.
بعدش چی؟
ما یک نقشه راه بسیار هیجان انگیز برای سال 2025 برنامه ریزی کرده ایم. یکی از اولویت های اصلی ارائه محدودیت های محاسباتی قابل تنظیم (حافظه، CPU و مدت زمان اجرا) است. به زودی یک به روز رسانی در مورد آن را اعلام خواهیم کرد.
منتظر عرضه های بعدی این هفته باشید. خواهید دید که چگونه همه این قطعات آینده مانند آجرهای لگو قرار می گیرند تا زندگی توسعه دهنده شما را آسان کنند.
اطلاعات بیشتر در مورد LW13
روز 1 – Supabase AI Assistant V2 روز 2 – توابع Supabase: وظایف پسزمینه و سوکتهای وب
مرحله ساخت
01 -OrioleDB عمومی آلفا
جلسات انجمن
ما هیجانزده هستیم که سه ویژگی مورد انتظار را اعلام کنیم: کارهای پسزمینه، ذخیرهسازی فایل زودگذر و WebSockets.
⚡️ اطلاعات بیشتر در هفته راه اندازی
از امروز می توانید از این ویژگی ها در هر پروژه ای استفاده کنید. بیایید کشف کنیم که چه چیزهای هیجان انگیزی می توانید با آنها بسازید.
https://www.youtube.com/watch?v=envrsJ8VfAU
وظایف پس زمینه
گاهی اوقات برای انجام کارهایی بیشتر از پاسخ به یک درخواست، به یک منطق پشتیبان نیاز دارید. برای مثال، ممکن است بخواهید دسته ای از فایل ها را پردازش کرده و نتایج را در Supabase Storage آپلود کنید. یا چندین ورودی را از یک جدول پایگاه داده بخوانید و برای هر ورودی، جاسازی ایجاد کنید.
با معرفی وظایف پس زمینه، اجرای این بارهای کاری طولانی مدت با توابع Edge بسیار آسان است.
ما یک روش جدید به نام معرفی کرده ایم EdgeRuntime.waitUntil
، که قول می پذیرد. این تضمین میکند که تا زمانی که وعده حل نشود، عملکرد خاتمه نمییابد.
پروژه های رایگان می توانند وظایف پس زمینه را حداکثر برای 150 ثانیه (2 متر 30 ثانیه) اجرا کنند. اگر در طرح پولی هستید، این محدودیت به 400 ثانیه (6 متر و 40 ثانیه) افزایش می یابد. ما قصد داریم در ماه های آینده محدودیت های انعطاف پذیرتری را معرفی کنیم.
هنگامی که عملکرد در شرف خاموش شدن است، می توانید با گوش دادن به اعلان ها مشترک شوید beforeunload
رویداد برای جزئیات بیشتر در مورد نحوه استفاده از وظایف پس زمینه، راهنما را بخوانید.
ذخیره سازی زودگذر
فراخوانیهای Edge Function اکنون به ذخیرهسازی زودگذر دسترسی دارند. این برای کارهای پسزمینه مفید است، زیرا به شما امکان میدهد فایلها را بخوانید و بنویسید /tmp
دایرکتوری برای ذخیره نتایج میانی
راهنمای نحوه دسترسی به حافظه موقت را بررسی کنید.
مثال: استخراج یک فایل فشرده و آپلود محتوای آن در Supabase Storage
بیایید به یک مثال در دنیای واقعی با استفاده از Background Tasks و Ephemeral Storage نگاه کنیم.
تصور کنید در حال ساخت یک برنامه آلبوم عکس هستید. شما می خواهید که کاربران شما عکس ها را به صورت یک فایل فشرده آپلود کنند. می توانید آنها را در یک تابع Edge استخراج کنید و آنها را در فضای ذخیره سازی آپلود کنید.
یکی از سادهترین راهها برای پیادهسازی استفاده از جریانها است:
import { ZipReaderStream } from 'https://deno.land/x/zipjs/index.js'
import { createClient } from 'jsr:@supabase/supabase-js@2'
const supabase = createClient(
Deno.env.get('SUPABASE_URL'),
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')
)
Deno.serve(async (req) => {
const uploadId = crypto.randomUUID()
const { error } = await supabase.storage.createBucket(uploadId, {
public: false,
})
for await (const entry of await req.body.pipeThrough(new ZipReaderStream())) {
// write file to Supabase Storage
const { error } = await supabase.storage
.from(uploadId)
.upload(entry.filename, entry.readable, {})
console.log('uploaded', entry.filename)
}
return new Response(
JSON.stringify({
uploadId,
}),
{
headers: {
'content-type': 'application/json',
},
}
)
})
اگر نسخه استریم را آزمایش کنید، هنگام بارگذاری فایل های فشرده با حجم بالای 100 مگابایت، با خطاهای محدودیت حافظه مواجه می شود. این به این دلیل است که نسخه استریم باید هر فایل را در یک آرشیو فشرده در حافظه نگه دارد.
در عوض میتوانیم آن را تغییر دهیم تا فایل فشرده را در یک فایل موقت بنویسیم. سپس، از یک کار پسزمینه برای استخراج و آپلود آن در Supabase Storage استفاده کنید. به این ترتیب ما فقط قسمت هایی از فایل فشرده را در حافظه می خوانیم.
import { BlobWriter, ZipReader, ZipReaderStream } from 'https://deno.land/x/zipjs/index.js'
import { createClient } from 'jsr:@supabase/supabase-js@2'
const supabase = createClient(
Deno.env.get('SUPABASE_URL'),
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')
)
let numFilesUploaded = 0
async function processZipFile(uploadId, filepath) {
const file = await Deno.open(filepath, { read: true })
const zipReader = new ZipReader(file.readable)
const entries = await zipReader.getEntries()
await supabase.storage.createBucket(uploadId, {
public: false,
})
await Promise.all(
entries.map(async (entry) => {
// read file entry
const blobWriter = new BlobWriter()
const blob = await entry.getData(blobWriter)
if (entry.directory) {
return
}
// write file to Supabase Storage
await supabase.storage.from(uploadId).upload(entry.filename, blob, {})
numFilesUploaded += 1
console.log('uploaded', entry.filename)
})
)
await zipReader.close()
}
// you can add a `beforeunload` event listener to be notified
// when Function Worker is about to terminate.
// use this to do any logging, save states.
globalThis.addEventListener('beforeunload', (ev) => {
console.log('function about to terminate: ', ev.detail.reason)
console.log('number of files uploaded: ', numFilesUploaded)
})
async function writeZipFile(filepath, stream) {
await Deno.writeFile(filepath, stream)
}
Deno.serve(async (req) => {
const uploadId = crypto.randomUUID()
await writeZipFile('/tmp/' + uploadId, req.body)
// process zip file in a background task
// calling EdgeRuntime.waitUntil() would ensure
// function worker wouldn't exit until the promise is completed.
EdgeRuntime.waitUntil(processZipFile(uploadId, '/tmp/' + uploadId))
return new Response(
JSON.stringify({
uploadId,
}),
{
headers: {
'content-type': 'application/json',
},
}
)
})
وب سوکت ها
Edge Functions اکنون از ایجاد اتصالات ورودی (سرور) و خروجی (کلینت) WebSocket پشتیبانی می کند. این امکان انواع موارد استفاده جدید را فراهم می کند.
مثال: ساختن یک رله احراز هویت شده برای OpenAI Realtime API
OpenAI اخیرا یک API Realtime را معرفی کرده است که از WebSockets استفاده می کند. اجرای این کار صرفاً در سمت کلاینت دشوار است زیرا باید کلید OpenAI خود را به صورت عمومی در معرض دید قرار دهید. OpenAI ساخت یک سرور برای احراز هویت درخواست ها را توصیه می کند.
با پشتیبانی جدید ما از WebSockets، میتوانید به راحتی این کار را در Edge Functions بدون ایستادن زیرساخت انجام دهید. علاوه بر این، می توانید از Supabase Auth برای احراز هویت کاربران و محافظت از استفاده OpenAI خود در برابر سوء استفاده استفاده کنید.
import { createClient } from 'jsr:@supabase/supabase-js@2'
const supabase = createClient(
Deno.env.get('SUPABASE_URL'),
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')
)
const OPENAI_API_KEY = Deno.env.get('OPENAI_API_KEY')
Deno.serve(async (req) => {
const upgrade = req.headers.get('upgrade') || ''
if (upgrade.toLowerCase() != 'websocket') {
return new Response("request isn't trying to upgrade to websocket.")
}
// WebSocket browser clients does not support sending custom headers.
// We have to use the URL query params to provide user's JWT.
// Please be aware query params may be logged in some logging systems.
const url = new URL(req.url)
const jwt = url.searchParams.get('jwt')
if (!jwt) {
console.error('Auth token not provided')
return new Response('Auth token not provided', { status: 403 })
}
const { error, data } = await supabase.auth.getUser(jwt)
if (error) {
console.error(error)
return new Response('Invalid token provided', { status: 403 })
}
if (!data.user) {
console.error('user is not authenticated')
return new Response('User is not authenticated', { status: 403 })
}
const { socket, response } = Deno.upgradeWebSocket(req)
socket.onopen = () => {
// initiate an outbound WebSocket connection to OpenAI
const url = 'wss://api.openai.com/v1/realtime?model=gpt-4o-realtime-preview-2024-10-01'
// openai-insecure-api-key isn't a problem since this code runs in an Edge Function
const openaiWS = new WebSocket(url, [
'realtime',
`openai-insecure-api-key.${OPENAI_API_KEY}`,
'openai-beta.realtime-v1',
])
openaiWS.onopen = () => {
console.log('Connected to OpenAI server.')
socket.onmessage = (e) => {
console.log('socket message:', e.data)
// only send the message if openAI ws is open
if (openaiWS.readyState === 1) {
openaiWS.send(e.data)
} else {
socket.send(
JSON.stringify({
type: 'error',
msg: 'openAI connection not ready',
})
)
}
}
}
openaiWS.onmessage = (e) => {
console.log(e.data)
socket.send(e.data)
}
openaiWS.onerror = (e) => console.log('OpenAI error: ', e.message)
openaiWS.onclose = (e) => console.log('OpenAI session closed')
}
socket.onerror = (e) => console.log('socket errored:', e.message)
socket.onclose = () => console.log('socket closed')
return response // 101 (Switching Protocols)
})
عملکرد و ثبات
در چند ماه گذشته، عملکرد، ثبات و DX بسیاری را در عملکردهای لبه بهبود دادهایم. در حالی که این بهبودها اغلب برای کاربران نهایی قابل مشاهده نیستند، آنها پایه و اساس ویژگی های جدیدی هستند که امروز اعلام می کنیم.
بعدش چی؟
ما یک نقشه راه بسیار هیجان انگیز برای سال 2025 برنامه ریزی کرده ایم. یکی از اولویت های اصلی ارائه محدودیت های محاسباتی قابل تنظیم (حافظه، CPU و مدت زمان اجرا) است. به زودی یک به روز رسانی در مورد آن را اعلام خواهیم کرد.
منتظر عرضه های بعدی این هفته باشید. خواهید دید که چگونه همه این قطعات آینده مانند آجرهای لگو قرار می گیرند تا زندگی توسعه دهنده شما را آسان کنند.
اطلاعات بیشتر در مورد LW13
روز 1 – Supabase AI Assistant V2
روز 2 – توابع Supabase: وظایف پسزمینه و سوکتهای وب
مرحله ساخت
01 -OrioleDB عمومی آلفا
جلسات انجمن