
# İşler

İşler, Queuety içindeki temel çalışma birimidir. Bir işleyici adı ve yük içeren bir iş dağıtın; çalışan işi alıp arka planda yürütür.

## İş dağıtımı

```php
use Queuety\Queuety;

Queuety::dispatch( 'send_email', [ 'to' => 'user@example.com' ] );
```

`dispatch()` bir `PendingJob` oluşturucu döndürür. Otomatik dağıtılmadan önce seçenekleri zincirleyebilirsiniz:

```php
use Queuety\Enums\Priority;

Queuety::dispatch( 'send_email', [ 'to' => 'user@example.com' ] )
    ->on_queue( 'emails' )
    ->with_priority( Priority::High )
    ->delay( 300 )
    ->max_attempts( 5 );
```

İş kimliğini hemen almak için `->id()` çağırın:

```php
$job_id = Queuety::dispatch( 'send_email', $payload )->id();
```

## İşleyici yazma

İşleyici, `Queuety\Handler` arayüzünü uygulayan herhangi bir sınıftır:

```php
use Queuety\Handler;

class SendEmailHandler implements Handler {
    public function handle( array $payload ): void {
        wp_mail( $payload['to'], $payload['subject'], $payload['body'] );
    }

    public function config(): array {
        return [
            'queue'           => 'emails',
            'max_attempts'    => 5,
            'backoff'         => 'exponential',
        ];
    }
}
```

`handle()` yöntemi iş yükünü alır ve işi gerçekleştirir. `config()` yöntemi isteğe bağlı varsayılan değerleri döndürür:

| Anahtar | Tür | Açıklama |
|---|---|---|
| `queue` | `string` | Varsayılan kuyruk adı |
| `max_attempts` | `int` | İş gömülmeden önceki, ilk çalıştırma da sayılan en fazla çalıştırma sayısı |
| `backoff` | `string` | Yeniden deneme geri çekilme stratejisi: `exponential`, `linear` veya `fixed` |
| `rate_limit` | `array` | `[max_executions, window_seconds]` olarak hız sınırı |
| `concurrency_group` | `string` | Maliyetli işleyiciler için paylaşılan çalışan kabul grubu |
| `concurrency_limit` | `int` | Bu grupta aynı anda işlenebilecek en fazla iş sayısı |
| `cost_units` | `int` | Ağırlıklı kuyruk veya sağlayıcı bütçeleri, iş akışı bütçeleri ve kabul buluşsal yöntemlerinde kullanılan göreli yürütme maliyeti |

Bu kaynak anahtarları, iş metaverilerinin, iş akışı bütçelerinin ve çalışan kabulünün birlikte çalıştığı Queuety kapsamındaki [Kaynak Yönetimi](https://queuety.inline0.dev/tr/docs/features/resource-management) modelinin parçasıdır.

İşleyiciyi kaydedin:

```php
Queuety::register( 'send_email', SendEmailHandler::class );
```

Ya da otomatik kayıt için [PHP özniteliklerini](https://queuety.inline0.dev/tr/docs/features/attributes) kullanın.

## Öncelik

İşlerin dört öncelik düzeyi vardır. Önceliği yüksek işler, çalışanlar tarafından önce alınır.

```php
use Queuety\Enums\Priority;

Queuety::dispatch( 'handler', $payload )->with_priority( Priority::Urgent );
```

| Düzey | Değer | Açıklama |
|---|---|---|
| `Priority::Low` | `0` | Varsayılan. Bekleyebilecek arka plan işleri. |
| `Priority::Normal` | `1` | Standart öncelik. |
| `Priority::High` | `2` | Low ve Normal'dan önce işlenir. |
| `Priority::Urgent` | `3` | İlk olarak işlenir. Ölçülü kullanın. |

## Gecikme

Bir işi, yalnızca belirtilen saniye sayısı geçtikten sonra kullanılabilir olacak şekilde geciktirin:

```php
Queuety::dispatch( 'send_reminder', $payload )->delay( 3600 ); // 1 hour
```

İş hemen eklenir, ancak gecikme süresi dolana kadar çalışanlar tarafından alınmaz.

## Benzersiz işler

Aynı işleyici ve yük için yinelenen gönderimleri önleyin. Aynı işleyici ve yüke sahip bekleyen veya işlenmekte olan bir iş zaten varsa, yeni bir iş oluşturmak yerine mevcut işin kimliği döndürülür.

```php
Queuety::dispatch( 'sync_inventory', [ 'sku' => 'ABC-123' ] )->unique();
```

## İş bağımlılıkları

Bir iş başka bir işe bağlı olabilir. Bağımlı iş tamamlanana kadar çalışan tarafından alınmaz.

```php
$first_id = Queuety::dispatch( 'import_data', $payload )->id();

Queuety::dispatch( 'send_notification', [ 'import_id' => $first_id ] )
    ->after( $first_id );
```

## Toplu gönderim

En yüksek aktarım hızı için tek bir çok satırlı INSERT ile birden fazla iş gönderin:

```php
$job_ids = Queuety::batch( [
    [ 'handler' => 'send_email', 'payload' => [ 'to' => 'a@example.com' ] ],
    [ 'handler' => 'send_email', 'payload' => [ 'to' => 'b@example.com' ] ],
    [ 'handler' => 'send_email', 'payload' => [ 'to' => 'c@example.com' ] ],
] );
```

Her öğe isteğe bağlı şu anahtarları içerebilir: `queue`, `priority`, `delay`, `max_attempts`.

## Yeniden deneme ve bekleme süresi

Bir iş istisna fırlattığında, Queuety işi `pending` durumuna geri alır ve toplamda `max_attempts` kez çalışana kadar gecikmeli bir `available_at` uygular (ilk çalıştırma da sayılır; bu nedenle `max_attempts( 3 )` en fazla iki yeniden deneme anlamına gelir). Her yeniden denemeden önceki gecikme, son başarısız çalıştırmanın numarası olan `attempt` değerini kullanan bekleme stratejisine göre belirlenir:

| Strateji | Gecikme formülü | Örnek (1., 2. ve 3. çalıştırmadan sonra) |
|---|---|---|
| `exponential` | 3600 ile sınırlandırılmış `2^attempt * 30` saniye | 60s, 120s, 240s |
| `linear` | `attempt * 60` saniye | 60s, 120s, 180s |
| `fixed` | `60` saniye | 60s, 60s, 60s |

Genel varsayılanı `wp-config.php` içinde ayarlayın:

```php
define( 'QUEUETY_RETRY_BACKOFF', 'linear' );
```

Ya da işleyici başına `config()` içinde ayarlayın:

```php
public function config(): array {
    return [ 'backoff' => 'exponential', 'max_attempts' => 5 ];
}
```

Ya da gönderim başına ayarlayın:

```php
Queuety::dispatch( 'handler', $payload )->max_attempts( 10 );
```

## Gömülmüş işler

Tüm yeniden deneme girişimleri tükendiğinde iş **gömülü** olarak işaretlenir. Gömülü işler inceleme için veritabanında kalır ancak işlenmez. Bunları elle yeniden deneyebilirsiniz. Elle yeniden deneme, girişim sayacını sıfırlamadan işi tekrar `pending` yapar; bu nedenle yeniden denenen gömülü iş bir kez daha çalıştırılır ve bu çalıştırma başarısız olursa tekrar gömülür:

```php
// Retry a specific buried job
Queuety::retry( $job_id );

// Retry all buried jobs
$count = Queuety::retry_buried();
```

Ya da CLI aracılığıyla:

```bash
wp queuety retry 42
wp queuety retry-buried
```

## Zaman aşımı

Queuety, maksimum yürütme süresi için bir `pcntl_alarm()` başlatır ve süre aşıldığında girişimi bir `TimeoutException` ile başarısız kılmak üzere tasarlanmıştır. Bu zaman aşımı şu anda uygulanmıyor ([#10](https://github.com/inline0/queuety/issues/10)): çalışan asenkron sinyalleri etkinleştirmediğinden uzun süren bir işleyici tamamlanana kadar çalışır; `sleep()` içinde engellenen bir işleyici ise alarm çaldığında kesilir ve ardından tamamlandı olarak işaretlenir. Zaman aşımını genel olarak yapılandırın:

```php
define( 'QUEUETY_MAX_EXECUTION_TIME', 300 ); // 5 minutes
```

`processing` durumunda `QUEUETY_STALE_TIMEOUT` saniyeden uzun süre takılı kalan işler otomatik olarak kurtarılır:

```php
define( 'QUEUETY_STALE_TIMEOUT', 600 ); // 10 minutes
```

Eski işleri elle kurtarın:

```bash
wp queuety recover
```

## Kuyruklar

İşler adlandırılmış kuyruklara gönderilir. Her çalışan bir kuyruğu veya sıralı bir kuyruk listesini işler (bkz. [Çalışanlar](https://queuety.inline0.dev/tr/docs/features/workers#multi-queue-priorities)):

```php
Queuety::dispatch( 'handler', $payload )->on_queue( 'emails' );
```

```bash
wp queuety work --queue=emails
```

Varsayılan kuyruk `default` şeklindedir. İş yüklerini yalıtmak için her kuyrukta ayrı çalışan süreçleri çalıştırabilirsiniz.

## Hız sınırlama

Bir işleyicinin belirli bir zaman aralığında ne sıklıkla çalışabileceğini sınırlayın:

```php
Queuety::dispatch( 'call_api', $payload )
    ->rate_limit( 10, 60 ); // max 10 executions per 60 seconds
```

Ayrıntılar için [Hız Sınırlama](https://queuety.inline0.dev/tr/docs/features/rate-limiting) bölümüne bakın.

## Gönderilebilir iş sınıfları

Queuety v0.6.0, sınıf tabanlı iş API yaklaşımını sunar. İşleyici adını, yükü ve işleyici sınıfını ayrı tutmak yerine her şeyi kapsayan tek bir sınıf tanımlarsınız: yük (türlü genel özellikler olarak), yürütme mantığı ve isteğe bağlı ara katman yazılımı.

### `Contracts\Job` arayüzü

```php
use Queuety\Contracts\Job;

interface Job {
    public function handle(): void;
}
```

Bir `Job` sınıfı, yükünü genel özellikler olarak tutar ve kendi mantığını `handle()` içinde yürütür. Ayrı bir `config()` yöntemi veya işleyici kaydı gerekmez.

### `Dispatchable` özelliği

İş sınıfınıza statik bir `dispatch()` yöntemi eklemek için `Dispatchable` özelliğini ekleyin:

```php
use Queuety\Contracts\Job;
use Queuety\Dispatchable;

class SendEmailJob implements Job {
    use Dispatchable;

    public function __construct(
        public readonly string $to,
        public readonly string $subject,
        public readonly string $body,
    ) {}

    public function handle(): void {
        wp_mail( $this->to, $this->subject, $this->body );
    }
}
```

Kurucu bağımsız değişkenlerini ileterek gönderin:

```php
SendEmailJob::dispatch( 'user@example.com', 'Welcome!', 'Hello there.' )
    ->on_queue( 'emails' )
    ->with_priority( Priority::High );
```

`Dispatchable` özelliği dahili olarak `Queuety::dispatch()` çağırır; bu nedenle tüm `PendingJob` seçenekleri (queue, priority, delay, max_attempts, unique, after) aynı şekilde çalışır.

### Serileştirme nasıl çalışır

Bir `Job` örneğini gönderdiğinizde, Queuety içindeki `JobSerializer` tam nitelikli sınıf adını işleyici, tüm genel özellikleri ise yük olarak çıkarır. Çalışan tarafında serileştirici, yük anahtarlarını kurucu parametre adlarıyla eşleştirerek örneği yeniden oluşturur. Değer taşıyan enum'lar temel değerlerine serileştirilir ve otomatik olarak geri yüklenir.

### İş özellikleri

İş sınıfları, yeniden deneme ve zaman aşımı davranışını denetlemek için genel özellikler tanımlayabilir. Çalışan bunları yansıma yoluyla okur ve otomatik olarak uygular.

```php
use Queuety\Contracts\Job;
use Queuety\Dispatchable;

class ImportProductsJob implements Job {
    use Dispatchable;

    public int $tries = 5;
    public int $timeout = 120;
    public array $backoff = [ 10, 30, 60, 120 ];
    public string $concurrency_group = 'imports';
    public int $concurrency_limit = 2;
    public int $cost_units = 4;

    public function __construct(
        public readonly int $supplier_id,
    ) {}

    public function handle(): void {
        // Import products...
    }
}
```

| Özellik | Tür | Açıklama |
|---|---|---|
| `$tries` | `int` | İş gömülmeden önceki maksimum girişim sayısı. Gönderim anındaki `max_attempts` değerini geçersiz kılar. |
| `$timeout` | `int` | Saniye cinsinden maksimum yürütme süresi. Genel `QUEUETY_MAX_EXECUTION_TIME` sabitini geçersiz kılar. `pcntl` gerektirir ve henüz uygulanmıyor (bkz. [Zaman aşımı](https://queuety.inline0.dev/tr/docs/jobs#timeout)). |
| `$backoff` | `array` | Her yeniden deneme girişimi için saniye cinsinden gecikme değerleri dizisi. Son değer sonraki girişimlerde de kullanılır. |
| `$concurrency_group` | `string` | Yüksek maliyetli işler için paylaşılan çalışan kabul grubu. |
| `$concurrency_limit` | `int` | Bu grupta eşzamanlı yürütülebilecek maksimum `processing` iş sayısı. `$concurrency_group` olmadan yok sayılır. |
| `$cost_units` | `int` | İş akışı bütçeleri ve çalışan kabulü için kullanılan göreli yürütme maliyeti. |

`$backoff` dizisi, artan yeniden deneme gecikmeleri sağlar. Örneğin `[10, 30, 60, 120]`, ilk yeniden denemenin 10 saniye, ikincinin 30 saniye, üçüncünün 60 saniye bekleyeceği; sonraki yeniden denemelerin ise 120 saniye bekleyeceği anlamına gelir.

Kaynaklarla ilgili özellikler, farklı maliyet profillerine sahip işleri temsil eden iş sınıfları için yararlıdır. Hızlı bir önbellek yenilemesi ile büyük bir sağlayıcı çağrısı da "bir iş" olabilir; ancak iş akışı bütçesi veya çalışan kabul kararı süreci güvenli sınırlar içinde tutmaya çalışırken bunların aynı ağırlıkta sayılması gerekmeyebilir.

İş akışı bütçeleri ve çalışan tarafındaki kabul dâhil tüm model için [Kaynak Yönetimi](https://queuety.inline0.dev/tr/docs/features/resource-management) bölümüne bakın.

### Başarısız kancası

Bir iş tüm yeniden deneme girişimleri tükendikten sonra gömüldüğünde Queuety, tanımlanmışsa iş örneğinde bir `failed()` yöntemi çağırır. Bunu temizlik, uyarı gönderme veya günlük kaydı için kullanın.

```php
use Queuety\Contracts\Job;
use Queuety\Dispatchable;

class ProcessPaymentJob implements Job {
    use Dispatchable;

    public int $tries = 3;

    public function __construct(
        public readonly int $order_id,
    ) {}

    public function handle(): void {
        // Process the payment...
    }

    public function failed( \Throwable $exception ): void {
        // Notify the team that payment processing failed permanently.
        error_log( "Payment failed for order {$this->order_id}: {$exception->getMessage()}" );
    }
}
```

`failed()` yöntemi son başarısızlığa neden olan istisnayı alır. İş örneği özgün yüküyle serileştirmeden çıkarılır; böylece tüm genel özellikler kullanılabilir olur.

### Koşullu gönderim

`Dispatchable` özelliği, koşullu gönderim için `dispatch_if()` ve `dispatch_unless()` yöntemlerini sağlar. Her ikisi de ilk bağımsız değişken olarak bir Boole koşulunu, ardından iş kurucusunun bağımsız değişkenlerini alır.

```php
// Only dispatch if the user has opted in to notifications.
SendEmailJob::dispatch_if( $user->wants_notifications, $user->email, 'Update', $body );

// Dispatch unless the feature flag is disabled.
SyncInventoryJob::dispatch_unless( $maintenance_mode, $sku );
```

Koşul `true` olduğunda `dispatch_if()` gönderim yapar ve `PendingJob` değerini döndürür. Koşul `false` olduğunda `null` döndürür.

Koşul `false` olduğunda `dispatch_unless()` gönderim yapar ve `PendingJob` değerini döndürür. Koşul `true` olduğunda `null` döndürür.

Her iki yöntem de gönderim sırasında `PendingJob` seçeneklerinin zincirleme kullanılmasını destekler:

```php
SendEmailJob::dispatch_if( $should_send, $to, $subject, $body )
    ?->on_queue( 'emails' )
    ?->with_priority( Priority::High );
```

### Eşzamanlı gönderim

Bir işi kuyruğa eklemeden geçerli süreçte hemen yürütmek için `Queuety::dispatch_sync()` kullanın. Bu, testler ve satır içi çalışması gereken işler için yararlıdır.

```php
use Queuety\Queuety;

// With a Job instance
Queuety::dispatch_sync( new SendEmailJob( to: 'user@example.com', subject: 'Hello', body: 'Hi!' ) );

// With a handler name and payload
Queuety::dispatch_sync( 'send_email', [ 'to' => 'user@example.com' ] );
```

İşin `handle()` yöntemi doğrudan çağrılır. Veritabanı satırı oluşturulmaz, çalışan kullanılmaz ve ara katman uygulanmaz.

### İş zincirleme

İş zincirleme, bir iş dizisini art arda yürütür. Zincirdeki her iş, önceki işin başarıyla tamamlanmasına bağlıdır. Herhangi bir iş başarısız olursa zincirdeki sonraki işler beklemede kalır.

#### `Queuety::chain()` kullanımı

```php
use Queuety\Queuety;

$first_job_id = Queuety::chain( [
    new FetchDataJob( $url ),
    new ProcessDataJob(),
    new NotifyCompleteJob(),
] )
    ->on_queue( 'pipeline' )
    ->catch( ChainFailedHandler::class )
    ->dispatch();
```

`Queuety::chain()`, kuyruğu ve başarısızlık işleyicisini ayarlamak için akıcı yöntemlere sahip bir `ChainBuilder` döndürür. `dispatch()` yöntemi, tüm işleri sıralı `depends_on` ilişkileriyle oluşturur ve ilk işin kimliğini döndürür.

#### `with_chain()` kullanımı

`Dispatchable` özelliği bir `with_chain()` yöntemi sağlar. Bu yöntem şu anda `Queuety::chain( $jobs )` ile eşdeğerdir: çağrıldığı sınıf zincire eklenmez ([#13](https://github.com/inline0/queuety/issues/13)), bu nedenle dizideki ilk işi de listeleyin:

```php
FetchDataJob::with_chain( [
    new FetchDataJob(),
    new ProcessDataJob(),
    new NotifyCompleteJob(),
] )
    ->on_queue( 'pipeline' )
    ->dispatch();
```

#### Zincir başarısızlığını ele alma

`catch()` kullanarak bir başarısızlık işleyici sınıfı kaydedin. İşleyici sınıfında bir `handle()` yöntemi bulunmalıdır. Zincirdeki herhangi bir iş kalıcı olarak gömüldüğünde çağrılır. Çalışan şu öğeleri destekler: `handle()`, `handle( Job $job )` ve `handle( Job $job, \Throwable $exception )`.

```php
class ChainFailedHandler {
    public function handle(): void {
        // Alert, clean up, etc.
    }
}
```

### Ara katman yazılımı ekleme

İş sınıfları, yürütmeyi saran ara katman yazılımını döndürmek için bir `middleware()` yöntemi tanımlayabilir:

```php
use Queuety\Contracts\Job;
use Queuety\Dispatchable;
use Queuety\Middleware\RateLimited;
use Queuety\Middleware\Timeout;

class CallOpenAIJob implements Job {
    use Dispatchable;

    public function __construct(
        public readonly string $prompt,
    ) {}

    public function handle(): void {
        // Call the API...
    }

    public function middleware(): array {
        return [
            new RateLimited( max: 60, window: 60 ),
            new Timeout( seconds: 120 ),
        ];
    }
}
```

Yerleşik ara katman yazılımları ve özel ara katman yazılımları yazma hakkında ayrıntılar için [Ara Katman Yazılımı](https://queuety.inline0.dev/tr/docs/features/middleware) bölümüne bakın.

### İşleyici tabanlı işlerle karşılaştırma

| | İşleyici tabanlı (v0.1+) | Sınıf tabanlı (v0.6+) |
|---|---|---|
| Gönderim | `Queuety::dispatch( 'send_email', $payload )` | `SendEmailJob::dispatch( $to, $subject )` |
| İşleyici | `Handler` arayüzünü uygulayan ayrı sınıf | Aynı sınıf `Contracts\Job` uygular |
| Yük | Türü belirtilmemiş `array $payload` | Türü belirtilmiş genel özellikler |
| Kayıt | `Queuety::register()` veya `#[QueuetyHandler]` | Gerekli değil (FQCN kullanır) |
| Ara katman yazılımı | Kullanılamaz | İsteğe bağlı `middleware()` yöntemi |
| Yapılandırma | `config()` yöntemi | İş özellikleri + `PendingJob` zinciri |

Her iki yaklaşım da tamamen desteklenir. Mevcut işleyici tabanlı işler değişiklik yapılmadan çalışmaya devam eder. Aynı projede her iki stili de kullanabilirsiniz.

## İş yaşam döngüsü

```
dispatch() -> pending -> processing -> completed
                  |           |
                  |           +-> exception -> pending (retry after backoff)
                  |                       |
                  |                       +-> buried (max attempts reached)
                  |
                  +-> delayed (available_at in the future)
```

| Durum | Açıklama |
|---|---|
| `pending` | Bir çalışan tarafından alınmayı bekliyor |
| `processing` | Şu anda yürütülüyor |
| `completed` | Başarıyla tamamlandı |
| `failed` | Ayrılmış; çalışan bugün bu durumu ayarlamıyor. Yeniden denenecek başarısız bir girişim `pending` durumuna geri döner |
| `buried` | Tüm yeniden deneme girişimleri tükendi |
