نقطة
  • الرئيسية
  • الخدمات
  • من نحن
  • الكتابات
  • تسجيل الدخول
الكتابات/tutorial/2026/07
● Tutorial24 يوليو 2026·30 دقيقة

Trigger.dev v4: مهام الخلفية وتدفقات الموافقة وأدوات الذكاء الاصطناعي في Next.js

انتقل من Trigger.dev v3 المتوقفة إلى v4 وابنِ خط معالجة مستندات متكاملاً مع تدفقات الموافقة باستخدام wait-for-token وجسر أدوات الذكاء الاصطناعي عبر schemaTask وقوائم انتظار محكومة التزامن في Next.js 15.

AI Bot
AI Bot
Author
·EN · FR · AR

لماذا Trigger.dev v4؟

أنهت Trigger.dev v3 دورة حياتها رسمياً في 1 يوليو 2026. إذا كان مشروعك لا يزال يستورد من @trigger.dev/sdk/v3، فقد توقفت مهام الخلفية عن العمل — البنية التحتية لسحابة v3 مُغلقة بالكامل.

v4 ليست مجرد تحديث شكلي. فهي تُعيد كتابة واجهة برمجة الـ hooks، وتُضيف نظام middleware، وتُدخل تدفقات الموافقة wait-for-token، وتُقدّم schemaTask — جسر يحوّل أي مهمة خلفية إلى أداة من الدرجة الأولى قابلة للاستخدام مع Vercel AI SDK. هذا الدرس يرشدك خلال مسار الهجرة ويبني خط معالجة مستندات متكاملاً يعرض كل ميزة رئيسية في v4.

المتطلبات المسبقة

  • Node.js 20 أو أحدث
  • مشروع Next.js 15 (App Router)
  • حساب على Trigger.dev — مجاني على trigger.dev
  • إلمام أساسي بـ TypeScript غير المتزامن

ما الذي ستبنيه

خط استيعاب مستندات بأربع مراحل:

  1. الاستيعاب — قبول الملفات المرفوعة وإضافة معالجتها إلى قائمة الانتظار
  2. التحليل — استخراج المحتوى بالذكاء الاصطناعي مع التحكم في التزامن
  3. الموافقة — الإيقاف المؤقت وانتظار مراجع بشري قبل النشر
  4. الإشعار — الاستئناف وإرسال تأكيد عند الموافقة

الخطوة 1: تثبيت SDK الإصدار v4

npm install @trigger.dev/sdk
npx trigger.dev@latest init

يكتب أمر init ملف trigger.config.ts في جذر المشروع ويُنشئ مجلد trigger/ لملفات المهام.

إذا كنت تُهاجر من v3، فأول تغيير هو مسار الاستيراد:

// قبل (v3)
import { task } from "@trigger.dev/sdk/v3";
 
// بعد (v4)
import { task } from "@trigger.dev/sdk";

اضبط مشروعك في trigger.config.ts:

// trigger.config.ts
import { defineConfig } from "@trigger.dev/sdk/config";
 
export default defineConfig({
  project: "proj_معرف_مشروعك",
  runtime: "node",
  maxDuration: 3600,
  dirs: ["./trigger"],
});

أضف مفتاح API الخاص بك في .env.local:

TRIGGER_SECRET_KEY=tr_dev_xxxxxxxxxxxx

الخطوة 2: مهمتك الأولى بـ v4

أبرز تغيير جذري في v4 هو واجهة برمجة معاملات الـ hook. في v3، كانت الـ hooks تستقبل وسائط إيجابية منفصلة. في v4، كل hook تستقبل كائناً مُفككاً واحداً.

// trigger/document-tasks.ts
import { task, logger } from "@trigger.dev/sdk";
 
export const ingestDocument = task({
  id: "ingest-document",
 
  // v4: معامل كائن واحد مُفكَّك لجميع الـ hooks
  onStartAttempt: ({ payload, ctx }) => {
    logger.info("بدء محاولة الاستيعاب", { runId: ctx.run.id });
  },
 
  onSuccess: ({ payload, output, ctx }) => {
    logger.info("نجح الاستيعاب", { docId: output.documentId });
  },
 
  onFailure: ({ payload, error, ctx }) => {
    logger.error("فشل الاستيعاب", { message: error.message });
  },
 
  // توقيع run() لم يتغير عن v3
  run: async (payload: { filename: string; url: string }, { ctx }) => {
    logger.info("معالجة المستند", { filename: payload.filename });
 
    await new Promise(resolve => setTimeout(resolve, 1000));
 
    return {
      documentId: `doc_${Date.now()}`,
      filename: payload.filename,
      status: "ingested",
    };
  },
});

ملاحظة: onStartAttempt هو خلَف v4 للـ hook المُهمَل onStart. استخدم onStartAttempt في كل الأكواد الجديدة.

الخطوة 3: التشغيل من Next.js

Server Action

// app/actions/document.ts
"use server";
 
import { tasks } from "@trigger.dev/sdk";
import type { ingestDocument } from "@/trigger/document-tasks";
 
export async function submitDocument(filename: string, url: string) {
  try {
    const handle = await tasks.trigger<typeof ingestDocument>(
      "ingest-document",
      { filename, url }
    );
    return { runId: handle.id };
  } catch (error) {
    return { error: "فشل إضافة المستند إلى قائمة الانتظار" };
  }
}

مسار API

// app/api/documents/route.ts
import { tasks } from "@trigger.dev/sdk";
import { NextResponse } from "next/server";
import type { ingestDocument } from "@/trigger/document-tasks";
 
export async function POST(request: Request) {
  const { filename, url } = await request.json();
 
  const handle = await tasks.trigger<typeof ingestDocument>(
    "ingest-document",
    { filename, url }
  );
 
  return NextResponse.json({ runId: handle.id });
}

الاستيراد من نوع type فقط يضمن عدم تسرب كود المهمة إلى حزمة العميل.

الخطوة 4: قوائم الانتظار والتزامن

استخدم queue() للتحكم في عدد التشغيلات المتزامنة — أمر حيوي لحماية قاعدة البيانات أو واجهات برمجة التطبيقات الخارجية.

// trigger/analysis-tasks.ts
import { task, queue } from "@trigger.dev/sdk";
 
const processingQueue = queue({
  name: "document-processing",
  concurrencyLimit: 5,
});
 
export const analyzeDocument = task({
  id: "analyze-document",
  queue: processingQueue,
 
  retry: {
    maxAttempts: 3,
    minTimeoutInMs: 1000,
    maxTimeoutInMs: 30000,
    factor: 2,
  },
 
  run: async (payload: { documentId: string; url: string }) => {
    const text = await fetch(payload.url).then(r => r.text());
    const wordCount = text.split(/\s+/).length;
 
    return {
      documentId: payload.documentId,
      wordCount,
      extractedAt: new Date().toISOString(),
    };
  },
});

يمكنك أيضاً تجاوز قائمة الانتظار عند التشغيل لتوجيه الأولويات:

// توجيه المستخدمين المميزين إلى قائمة انتظار بتزامن أعلى
const handle = await analyzeDocument.trigger(
  { documentId, url },
  { queue: "premium-users" }
);

الخطوة 5: Wait-for-Token — تدفق الموافقة البشرية

أقوى بدائية جديدة في v4 هي رمز نقطة الانتظار (waitpoint token). تتوقف المهمة مؤقتاً في منتصف تنفيذها ولا تستأنف إلا عندما يُكمل نظام خارجي ذلك الرمز — سواء بعد دقائق أو ساعات أو أيام — دون احتلال خيط خادم.

// trigger/approval-tasks.ts
import { task, wait } from "@trigger.dev/sdk";
 
export const awaitDocumentApproval = task({
  id: "await-document-approval",
  maxDuration: 86400, // توقف مؤقت حتى 24 ساعة
 
  run: async (payload: { documentId: string; reviewerEmail: string }) => {
    // إنشاء رمز مرتبط بهذه التشغيلة
    const token = await wait.createToken({
      timeout: "24h",
      tags: [`doc:${payload.documentId}`],
    });
 
    // إرسال بريد إلكتروني يحتوي على رابط يتضمن token.id
    await notifyReviewer(payload.reviewerEmail, payload.documentId, token.id);
 
    // المهمة تتوقف هنا — تستأنف عند اكتمال الرمز
    const result = await wait.forToken<{ approved: boolean; notes: string }>(token);
 
    if (!result.output.approved) {
      throw new Error(`رُفض المستند: ${result.output.notes}`);
    }
 
    return { approved: true, notes: result.output.notes };
  },
});
 
async function notifyReviewer(email: string, docId: string, tokenId: string) {
  // إرسال بريد مع رابط: /api/review?token=tokenId&doc=docId
  console.log(`تم إرسال رابط الموافقة إلى ${email} للمستند ${docId}`);
}

إكمال الرمز من مسار API

// app/api/review/route.ts
import { runs } from "@trigger.dev/sdk";
import { NextResponse } from "next/server";
 
export async function POST(request: Request) {
  const { tokenId, approved, notes } = await request.json();
 
  // إكمال نقطة الانتظار — المهمة تستأنف فوراً
  await runs.completeToken(tokenId, { approved, notes });
 
  return NextResponse.json({ ok: true });
}

بدائية wait.forToken تتعامل مع أي تسليم غير متزامن كان سيتطلب تقليدياً polling أو webhooks.

الخطوة 6: schemaTask كأداة ذكاء اصطناعي

تُقدّم v4 schemaTask — نوعاً من المهام يُصرّح بمخطط Zod. هذا يُفعّل ai.toolExecute، الذي يحوّل أي مهمة خلفية إلى أداة يمكن لنماذج اللغة استدعاؤها عبر Vercel AI SDK.

// trigger/ai-tasks.ts
import { schemaTask } from "@trigger.dev/sdk";
import { z } from "zod";
 
export const summarizeDocument = schemaTask({
  id: "summarize-document",
  description: "استخراج ملخص والموضوعات الرئيسية من رابط مستند",
  schema: z.object({
    documentId: z.string(),
    url: z.string().url(),
    maxWords: z.number().int().min(50).max(500).default(200),
  }),
  run: async ({ documentId, url, maxWords }) => {
    const text = await fetch(url).then(r => r.text());
    const words = text.split(/\s+/).slice(0, maxWords);
    return {
      documentId,
      summary: words.join(" "),
      topicCount: Math.min(3, Math.floor(words.length / 50)),
    };
  },
});

ربطه كأداة Vercel AI SDK

// lib/document-agent.ts
import { generateText, tool } from "ai";
import { anthropic } from "@ai-sdk/anthropic";
import { ai } from "@trigger.dev/sdk/ai";
import { summarizeDocument } from "@/trigger/ai-tasks";
 
const summarizeTool = tool({
  description: summarizeDocument.description ?? "تلخيص مستند",
  inputSchema: summarizeDocument.schema!,
  execute: ai.toolExecute(summarizeDocument),
});
 
export async function runDocumentAgent(userPrompt: string) {
  const { text } = await generateText({
    model: anthropic("claude-sonnet-5"),
    prompt: userPrompt,
    tools: { summarizeDocument: summarizeTool },
    maxSteps: 5,
  });
  return text;
}

عندما يستدعي النموذج summarizeDocument، تعمل مهمة Trigger.dev في الخلفية — مع إعادة المحاولات والتحكم في التزامن والمراقبة في الوقت الفعلي — بدلاً من التنفيذ المباشر داخل مسار API.

الخطوة 7: المهام المجدولة (Cron)

// trigger/scheduled-tasks.ts
import { schedules } from "@trigger.dev/sdk";
 
export const dailyCleanup = schedules.task({
  id: "daily-cleanup",
  cron: "0 2 * * *", // 02:00 UTC كل يوم
 
  run: async (payload) => {
    const { timestamp, lastTimestamp } = payload;
 
    const cutoff = new Date(timestamp);
    cutoff.setDate(cutoff.getDate() - 30);
 
    // payload.lastTimestamp غير معرّف في التشغيل الأول
    const since = lastTimestamp ?? cutoff;
 
    const deleted = await deleteDocumentsOlderThan(cutoff);
    return { deleted, runAt: timestamp.toISOString(), since: since.toISOString() };
  },
});
 
async function deleteDocumentsOlderThan(cutoff: Date): Promise<number> {
  // استعلام قاعدة البيانات هنا
  return 0;
}

لا حاجة لأي إعداد إضافي — حقل cron يُسجّل الجدول الزمني تلقائياً عند النشر.

الخطوة 8: hooks دورة الحياة الجديدة في v4

تُضيف v4 hooks تُطلَق حول نقاط الانتظار، مما يمنحك رؤية على التشغيلات المتوقفة مؤقتاً:

// trigger/monitored-task.ts
import { task, logger } from "@trigger.dev/sdk";
 
export const monitoredTask = task({
  id: "monitored-task",
 
  // تُطلَق عند دخول التشغيلة في نقطة انتظار
  onWait: ({ payload, ctx }) => {
    logger.info("المهمة متوقفة مؤقتاً عند نقطة انتظار", { runId: ctx.run.id });
  },
 
  // تُطلَق عند حل نقطة الانتظار واستئناف التشغيلة
  onResume: ({ payload, ctx }) => {
    logger.info("المهمة استؤنفت من نقطة الانتظار", { runId: ctx.run.id });
  },
 
  // تُطلَق بعد العودة الناجحة من دالة run
  onComplete: ({ payload, output, ctx }) => {
    logger.info("اكتملت المهمة", { runId: ctx.run.id, output });
  },
 
  // تُطلَق عند إلغاء التشغيلة عبر لوحة التحكم أو API
  onCancel: ({ payload, ctx }) => {
    logger.warn("تم إلغاء المهمة", { runId: ctx.run.id });
  },
 
  run: async (payload: { documentId: string }) => {
    return { processed: payload.documentId };
  },
});

تُكمّل هذه الـ hooks الـ hooks الموجودة onSuccess وonFailure وonStartAttempt، وهي مفيدة لإرسال المقاييس إلى Datadog أو PostHog أو أي نظام مراقبة.

الخطوة 9: التشغيل الدُفعي (تغيير API في v4)

تغيّرت API الدُفعية في v4. الآن تُستعاد النتائج باستخدام batch.retrieve() بدلاً من الوصول المباشر إلى batchHandle.runs:

import { tasks, batch } from "@trigger.dev/sdk";
import type { ingestDocument } from "@/trigger/document-tasks";
 
const documents = [
  { filename: "تقرير-أ.pdf", url: "https://example.com/a.pdf" },
  { filename: "تقرير-ب.pdf", url: "https://example.com/b.pdf" },
  { filename: "تقرير-ج.pdf", url: "https://example.com/c.pdf" },
];
 
const batchHandle = await tasks.batchTrigger(
  documents.map(doc => [ingestDocument, doc] as const)
);
 
// v3: batchHandle.runs — مُزال في v4
// v4: استرجاع منفصل
const batchResult = await batch.retrieve(batchHandle.batchId);
console.log(`تم إضافة ${batchResult.runs.length} تشغيلات إلى قائمة الانتظار`);

الخطوة 10: التطوير والنشر

التطوير المحلي

npx trigger.dev@latest dev

يدفق هذا الأمر سجلات المهام إلى طرفيتك ويُعيد التحميل تلقائياً عند حفظ ملفات المهام. خادم Next.js dev يعمل بشكل منفصل.

النشر على سحابة Trigger.dev

npx trigger.dev@latest deploy

GitHub Actions CI

- name: نشر مهام Trigger.dev
  run: npx trigger.dev@latest deploy --ci
  env:
    TRIGGER_SECRET_KEY: ${{ secrets.TRIGGER_SECRET_KEY }}

مرجع الهجرة: من v3 إلى v4

ما الذي تغيّرv3v4
مسار الاستيراد@trigger.dev/sdk/v3@trigger.dev/sdk
معاملات الـ hookوسائط إيجابيةكائن مُفكَّك واحد
اسم الـ hookonStartonStartAttempt (مُفضَّل)
نتائج الدُفعةbatchHandle.runsbatch.retrieve(id).runs
تدفقات الموافقةغير متاحةwait.createToken وwait.forToken
جسر أدوات الذكاء الاصطناعيغير متاحschemaTask وai.toolExecute
hooks الإيقاف/الاستئنافغير متاحةonWait وonResume وonComplete وonCancel

استكشاف الأخطاء وإصلاحها

المهمة لا تعمل: تحقق من أن TRIGGER_SECRET_KEY يطابق مشروعك. شغّل npx trigger.dev@latest whoami للتحقق من الاتصال.

التشغيلة عالقة في حالة "waiting": تم إنشاء رمز نقطة انتظار لكن لم يُكتمل. اتصل بـ runs.completeToken من نقطة نهاية الموافقة، أو ألغِ التشغيلة من لوحة تحكم Trigger.dev.

أخطاء TypeScript على معاملات الـ hook: لا تزال تستخدم الأسلوب الإيجابي لـ v3. اجمعها في كائن مُفكَّك واحد كما هو موضح في الخطوة 2.

batchHandle.runs غير معرَّف: تستخدم API الدُفعية القديمة لـ v3. انتقل إلى batch.retrieve(batchHandle.batchId) كما هو موضح في الخطوة 9.

الخطوات التالية

  • بحث LanceDB المتجهي في Next.js — تخزين تضمينات المستندات المستخرجة بالذكاء الاصطناعي والاستعلام عنها
  • AI SDK 7 HarnessAgent — تنسيق أدوات schemaTask من Trigger.dev مع HarnessAgent
  • بوابة LiteLLM Proxy — توجيه استدعاءات الذكاء الاصطناعي عبر بوابة مستضافة ذاتياً بميزانيات لكل فريق

خلاصة

يُقدّم Trigger.dev v4 تحسينات جوهرية على v3: API hooks أنظف، وwait-for-token لتدفقات الإنسان في الحلقة غير المتزامنة، وschemaTask لتكامل أدوات الذكاء الاصطناعي، وhooks دورة حياة جديدة للمراقبة حول نقاط الانتظار. مع إغلاق v3 بالكامل منذ يوليو 2026، الهجرة ليست اختيارية — لكن الترقية مباشرة، والميزات الجديدة تستحق الجهد.

● الوسوم
#nextjs#typescript#background-jobs#ai#serverless#intermediate#30 دقيقة قراءة
● مشاركة
● هل لديك سؤال؟

تحدث مع وكيل نقطة بشأن هذا المقال.

AI Bot
AI Bot
Author · noqta
متابعة ↗

● اقرأ التالي

بروتوكول A2A بلغة TypeScript: بناء وكلاء ذكاء اصطناعي متوافقين مع معيار Agent2Agent (2026)
● Tutorial

بروتوكول A2A بلغة TypeScript: بناء وكلاء ذكاء اصطناعي متوافقين مع معيار Agent2Agent (2026)

6 يوليو 2026
بناء وكيل ACP بلغة TypeScript: اربط أي محرّر بوكيل الذكاء الاصطناعي الخاص بك (2026)
● Tutorial

بناء وكيل ACP بلغة TypeScript: اربط أي محرّر بوكيل الذكاء الاصطناعي الخاص بك (2026)

30 يونيو 2026
بروتوكول AG-UI مع Next.js: بث وكلاء الذكاء الاصطناعي إلى واجهتك بأحداث مُنمّطة (2026)
● Tutorial

بروتوكول AG-UI مع Next.js: بث وكلاء الذكاء الاصطناعي إلى واجهتك بأحداث مُنمّطة (2026)

9 يوليو 2026
نقطة
الشروط والأحكام · سياسة الخصوصية
أدوات عربية مجانية
  • لوحة مفاتيح عربية
  • حروف الهجاء
  • تشكيل النصوص
  • عكس الكلام
  • زخرفة عربي
  • كل موارد العربية
الخدمات
  • أتمتة الذكاء الاصطناعي
  • وكلاء الذكاء الاصطناعي
  • أتمتة تجربة العملاء
  • Vibe Coding
  • إدارة المشاريع
  • ضمان الجودة
  • تطوير الويب
  • تكامل API
  • تطبيقات الأعمال
  • الصيانة
  • Low-Code/No-Code
الروابط
  • معلومات عنا
  • كيف نعمل؟
  • الأخبار
  • الدروس التعليمية
  • المدونة
  • تواصل معنا
  • الأسئلة الشائعة
  • الموارد
المناطق
  • السعودية
  • الإمارات
  • قطر
  • البحرين
  • عُمان
  • ليبيا
  • تونس
  • الجزائر
  • المغرب
الشركة
  • نقطة، تونس، الهاتف +216 24 309 128
© نقطة. جميع الحقوق محفوظة.