Files
upstream-mirror e7da97194a
Some checks failed
App Prod-Parity E2E Dispatch / dispatch (push) Failing after 10s
CD Storybook UI / build (push) Failing after 3m25s
CD Storybook UI / dispatch (push) Has been skipped
CD deploy main / website-changed-files (push) Successful in 18m8s
CI Agent Skills / changed-files-check (push) Successful in 18m9s
CI Create App E2E minimal / changed-files-check (push) Successful in 24s
CI Create App / changed-files-check (push) Successful in 26s
CI Docs / changed-files-check (push) Successful in 26s
CI Emails / changed-files-check (push) Successful in 28s
CI Example App Hello World / changed-files-check (push) Successful in 23s
CI Front / changed-files-check (push) Has been skipped
CI Example App Postcard / changed-files-check (push) Successful in 27s
CI UI / changed-files-check (push) Has been skipped
CI Utils Test / changed-files-check (push) Successful in 45s
CI Twenty Apps / discover (push) Successful in 1m3s
CD deploy main / deploy-main (push) Failing after 3s
CI Agent Skills / agent-skills-validate (push) Has been skipped
CI Create App / create-app-test (lint) (push) Has been skipped
CI Emails / emails-test (push) Has been skipped
CI Front / front-task (lingui:compile) (push) Has been skipped
CI Front / front-task (lint) (push) Has been skipped
CI Example App Postcard / example-app-postcard (push) Has been skipped
CI UI / ui-task (lint) (push) Has been skipped
CI UI / ui-task (pack-size) (push) Has been skipped
CI UI / ui-task (size) (push) Has been skipped
CI UI / ui-task (test) (push) Has been skipped
CI UI / ui-task (typecheck) (push) Has been skipped
CI Utils Test / utils-test (push) Has been skipped
CI Twenty Apps / ${{ matrix.app.name }} (push) Has been skipped
CI Emails / ci-emails-status-check (push) Successful in 2s
CI Example App Hello World / ci-example-app-hello-world-status-check (push) Successful in 2s
CI Example App Postcard / ci-example-app-postcard-status-check (push) Successful in 3s
CI UI / ui-sb-test (push) Has been skipped
CI Utils Test / ci-utils-test-status-check (push) Successful in 2s
CI Twenty Apps / ci-twenty-apps-status-check (push) Successful in 2s
CI UI / ci-ui-status-check (push) Successful in 2s
CI Desktop / desktop (push) Failing after 1m8s
Push docs to Crowdin / Push documentation to Crowdin (push) Failing after 55s
Push translations to Crowdin / Extract and upload translations (push) Failing after 5s
Push website translations to Crowdin / Extract and upload website translations (push) Failing after 5s
CI Create App / create-app-test (test) (push) Has been skipped
CI Create App / create-app-test (typecheck) (push) Has been skipped
CI Docs / docs-lint (push) Has been skipped
CI Example App Hello World / example-app-hello-world (push) Has been skipped
CI Front / front-task (lingui:extract) (push) Has been skipped
CI Front / front-task (test) (push) Has been skipped
CI Front / front-task (typecheck) (push) Has been skipped
CI UI / ui-sb-build (push) Failing after 1m32s
CI Twenty Apps / ${{ matrix.app.name }} (${{ matrix.server-source }}) (push) Has been skipped
CI Agent Skills / agent-skills-publish (push) Has been skipped
CI Create App / ci-create-app-status-check (push) Successful in 2s
CI Agent Skills / agent-skills-remote-source (push) Has been skipped
CI Create App E2E minimal / create-app-e2e-minimal (push) Has been cancelled
CI E2E Main / e2e-test (push) Has been cancelled
CI Front / front-sb-build (push) Has been cancelled
CI Front / front-build (push) Has been cancelled
CI Create App E2E minimal / ci-create-app-e2e-minimal-status-check (push) Has been cancelled
CI E2E Main / ci-e2e-main-status-check (push) Has been cancelled
CI E2E Main / notify-main-ci-failure (push) Has been cancelled
CI E2E Main / qa-scout-comment (push) Has been cancelled
CI Front / front-sb-test (push) Has been cancelled
CI Front / front-sb-screenshots (push) Has been cancelled
CI Front / ci-front-status-check (push) Has been cancelled
DPA Sub-Processor Sync / sync-subprocessors (push) Failing after 3s
AI Catalog Sync / sync-catalog (push) Failing after 2s
snapshot of https://github.com/twentyhq/twenty.git (main, 2026-09-17; blobs > 131072B omitted)
2026-09-17 23:28:13 +05:00

198 lines
11 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: Arka Plan İşleri
description: Uzun süren veya hız sınırına takılan işleri, her şeyi satır içi yapmak yerine başka bir mantık fonksiyonu çalıştırmasını kuyruğa alarak Twenty işleyicilerine devredin.
icon: layer-group
---
Bir mantık fonksiyonu çalıştırması, `timeoutSeconds` değeriyle sınırlandırılır (en fazla 900 saniye). Bu sürede tamamlanamayan her şey — tam bir yeniden eşitleme, kayıt başına dağıtım, sizi hız sınırına takan üçüncü taraf bir API — daha küçük çalıştırmalara bölünmek zorundadır.
`enqueueJobs` tam olarak bunu yapar: Twenty işleyicilerinden, uygulamanızın mantık fonksiyonlarından birini daha sonra, her veri yükü için bir kez, her çalıştırma kendi işleminde ve kendi zaman aşımı bütçesiyle çalıştırmasını ister. Çağıran hemen döner.
```text
┌─────────────────┐ enqueueJobs(...) ┌──────────────┐ ┌────────────────────┐
│ Logic function │ ─────────────────▶ │ Job queue │──▶│ Logic function │
│ (returns now) │ │ (workers) │ │ (fresh run/timeout)│
└─────────────────┘ └──────────────┘ └────────────────────┘
```
## Çalıştırmaları kuyruğa al
`enqueueJobs` fonksiyonunu `twenty-sdk/logic-function` içinden içe aktarın, çalıştırılacak mantık fonksiyonunun `universalIdentifier` değerini belirtin ve kuyruğa almak üzere her çalıştırma için bir veri yükü iletin.
```ts src/logic-functions/sync-all-contacts.ts
import { enqueueJobs } from 'twenty-sdk/logic-function';
await enqueueJobs({
logicFunctionUniversalIdentifier: '9f1c3d7e-51b8-4a29-8f0d-7c4e2a6b1d33',
payloads: [{ page: 1 }],
});
```
Her çalıştırma, tıpkı diğer tetikleyicilerde olduğu gibi, veri yükünü işleyici argümanı olarak alır. Hedef, çağrıyı yapanla **aynı uygulamaya** ait olmalıdır — başka bir uygulamanın fonksiyonunu kuyruğa alma girişimi `Logic function not found` hatasıyla reddedilir ve hiçbir şey kuyruğa alınmaz. Tek bir çağrı en fazla `200` veri yükünü kabul eder.
<Note>
`enqueueJobs`, işler kabul edilir edilmez döner; işler çalıştığında değil. Hedeflerin sonuçlarını döndürmez — bunları daha sonra okumanız gerekiyorsa, her hedefin ürettiği veriyi [anahtar-değer deposuna](/l/tr/developers/extend/apps/logic/key-value-store) veya bir çalışma alanı kaydına yazmasını sağlayın.
</Note>
<Note>
Her çağrıda tek bir işi kuyruğa alan eski `enqueueJob` yardımcısı kullanım dışı bırakılmıştır. Bunun yerine tek öğeli bir `payloads` listesiyle `enqueueJobs` kullanın.
</Note>
## İş seçenekleri
Seçenekler, toplu işlemdeki her çalıştırma için geçerlidir.
| Seçenek | Varsayılan | Aralık | Ne yapar |
| ------------ | ---------- | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `retryLimit` | `0` | `0`–`10` | Toplam ek kuyruk denemeleri. Uygulama tarafından istenen yeniden denemeler `3` ile sınırlandırılmıştır. Bunu yalnızca iki kez çalıştırılması güvenli olan işleyiciler için artırın. |
| `delayMs` | `0` | `0`–`604800000` (7 gün) | Çalıştırmalar uygun hale gelmeden önce bu kadar süre bekleyin. |
```ts
await enqueueJobs({
logicFunctionUniversalIdentifier: '9f1c3d7e-51b8-4a29-8f0d-7c4e2a6b1d33',
payloads: [{ page: 1 }],
retryLimit: 3,
delayMs: 60_000,
});
```
<Note>
**Öncelik henüz yapılandırılamıyor.** Kuyruğa alınan işler her zaman en düşük öncelikte çalışır, bu nedenle platform işleri asla uygulama işlerinin arkasında gecikmez. Öncelik üzerinde denetim yakında geliyor.
</Note>
Kuyruğa alınan çalıştırma, onu kuyruğa alan fonksiyonun etkin kullanıcı bilgisini devralır; böylece aynı izinlerle hareket eder.
## Geçici bir hatayı yeniden dene.
Twenty, uygulama kodundan kaynaklanan her özel durumu yeniden denemez. Normal şekilde fırlatılan bir hata kalıcı hata olarak değerlendirilir. Geçici bir hata için, kuyruktaki bir mantık işlevi `RetryableLogicFunctionError` fırlatarak en fazla üç yeniden deneme isteyebilir.
```ts
import {
type LogicFunctionExecutionContext,
RetryableLogicFunctionError,
} from 'twenty-sdk/logic-function';
export const handler = async (
_payload: unknown,
{ retryCount, maxRetries }: LogicFunctionExecutionContext,
) => {
const response = await fetch('https://api.example.com/contacts');
if (response.status === 429 || response.status >= 500) {
throw new RetryableLogicFunctionError(
`The contacts API is temporarily unavailable (${response.status}); retry ${retryCount} of ${maxRetries}`,
);
}
};
```
Mümkün olduğunda doğrudan `RetryableLogicFunctionError` fırlatın. Bunu genişletirseniz `name` değerini değiştirmeyin: Twenty, serileştirilmiş `RetryableLogicFunctionError` adını yürütme çalışma zamanları arasında tanır.
`retryCount`, ilk yürütme için `0` değerindedir ve yalnızca uygulama kodu yeniden deneme istediğinde artar. `maxRetries` en fazla `3` değerindedir ve kuyruktaki işin genel yeniden deneme sınırı daha düşük olduğunda daha düşük olabilir. Platform hataları, kuyruğun genel güvenlik bütçesini tüketmeye devam etse de `retryCount` değerini artırmaz.
Kuyruk, yeniden deneme girişimlerini üstel geri çekilme ve titreşimle geciktirir. Kesin gecikme kasıtlı olarak garanti edilmez; bu nedenle uygulama kodu, yeniden denemenin kesin bir zamanda gerçekleşmesine bağlı olmamalıdır. `maxRetries` değerine ulaşıldığında, başka bir yürütme olmadan başka bir `RetryableLogicFunctionError` nihai uygulama hatası olarak kaydedilir.
<Warning>
Yeniden denemeler tüm işleyiciyi yeniden çalıştırır ve bazı yan etkiler başarılı olduktan sonra gerçekleşebilir. Yeniden deneme istemeden önce işleyiciyi idempotent hale getirin.
</Warning>
## Kullanım örneği: uzun bir eşitleme boyunca sayfalama yapma
Klasik biçim, bir sonraki imleçle *kendini* kuyruğa alan bir fonksiyondur. Her çalıştırma, kendi zaman aşımı süresinin oldukça altında bir sayfa işi tamamlar ve hiçbir şey kalmadığında zincir durur.
```ts src/logic-functions/sync-contacts-page.ts
import { defineLogicFunction } from 'twenty-sdk/define';
import { enqueueJobs } from 'twenty-sdk/logic-function';
const SYNC_CONTACTS_PAGE = '9f1c3d7e-51b8-4a29-8f0d-7c4e2a6b1d33';
const handler = async (params: { cursor?: string }) => {
const { contacts, nextCursor } = await fetchContactsPage(params.cursor);
await importContacts(contacts);
if (nextCursor) {
await enqueueJobs({
logicFunctionUniversalIdentifier: SYNC_CONTACTS_PAGE,
payloads: [{ cursor: nextCursor }],
delayMs: 2_000,
});
}
return { imported: contacts.length, done: !nextCursor };
};
export default defineLogicFunction({
universalIdentifier: SYNC_CONTACTS_PAGE,
name: 'sync-contacts-page',
timeoutSeconds: 120,
handler,
});
```
## Kayıt başına fan-out
İş doğal olarak öğe bazındaysa, tek bir çağrıda her öğe için bir işi kuyruğa alın ve döngüyü satır içi çalıştırmak yerine çalışanların bunları paralel olarak işlemesine izin verin.
```ts
const companies = await listCompaniesToEnrich();
await enqueueJobs({
logicFunctionUniversalIdentifier: ENRICH_COMPANY,
payloads: companies.map((company) => ({ companyId: company.id })),
retryLimit: 2,
});
```
## Uzun süre çalışan işler için iyi uygulamalar
Hemen hemen tüm uzun işleri kapsayan iki kural: **döngü kurmak yerine özyineleme (recurse) kullanın** ve **her çalıştırmada sınırlı büyüklükte bir parçayı işleyin**.
Her şeyi tek seferde yapmaya çalışan bir çalıştırma, hata senaryosudur — zaman aşımına takılır ve yeniden denemede her şeyi baştan başlatır. Bunun yerine, bir parçayı `timeoutSeconds` süresinin içinde rahatça bitecek şekilde boyutlandırın, konumunuzu kalıcı hale getirin ve sonraki çalıştırmayı kuyruğa alın.
```ts src/logic-functions/enrich-companies-batch.ts
import { defineLogicFunction } from 'twenty-sdk/define';
import { enqueueJobs, kv } from 'twenty-sdk/logic-function';
const ENRICH_COMPANIES_BATCH = '3f9d1c02-8a44-4f0e-b1d7-9c2e5a7b4f10';
const CHUNK_SIZE = 50;
const handler = async (params: { offset?: number }) => {
const offset = params.offset ?? 0;
const companies = await listCompaniesToEnrich({
offset,
limit: CHUNK_SIZE,
});
for (const company of companies) {
await enrichCompany(company);
}
await kv.set('enrich:progress', { offset: offset + companies.length });
if (companies.length === CHUNK_SIZE) {
await enqueueJobs({
logicFunctionUniversalIdentifier: ENRICH_COMPANIES_BATCH,
payloads: [{ offset: offset + CHUNK_SIZE }],
});
}
return { processed: companies.length, done: companies.length < CHUNK_SIZE };
};
export default defineLogicFunction({
universalIdentifier: ENRICH_COMPANIES_BATCH,
name: 'enrich-companies-batch',
timeoutSeconds: 300,
handler,
});
```
Bunu işe yarar kılanlar:
* **Parça boyutunu ortalamaya değil, en yavaş öğeye göre belirleyin.** `CHUNK_SIZE × en kötü durum öğe süresi` değeri, pay bırakacak şekilde `timeoutSeconds` içine sığmalıdır, yoksa parça kuyruğunun sonundakiler çalıştırma kesildiğinde kaybolur.
* **Sonlandırma koşulunu açık hale getirin.** Yalnızca tam dolu bir parça döndüğü sürece özyineleme yapın. Yalnızca "sonuç yok" durumunda duran bir zincir, kaynak ortada bir yerde kısa bir sayfa döndürürse sonsuza dek devam eder.
* **Sonraki çalıştırmayı kuyruğa almadan önce ilerlemeyi kalıcı hale getirin,** böylece başarısız olan bir halka baştan başlamak yerine son tamamlanan parçadan yeniden başlar.
* **Her parçayı idempotent tutun.** Bir yeniden denemeden sonra aynı parçanın yeniden işlenmesi, iki kez yazma yapmamalıdır — yazma işlemlerini, işlediğiniz kayıt veya harici kimlik üzerinde anahtarlandırın.
* **Oran sınırlamalı bir üçüncü tarafla çalışırken, tek bir dev fan-out yerine parçalara bölünmüş bir zinciri tercih edin;** `delayMs` içeren bir zincir kendi hızını ayarlar, oysa binlerce işi bir kerede kuyruğa almak, hepsinin aynı anda uygun hale gelmesine neden olur.