Tasarım / Mimarlık soru: uzaktan hizmetleri ile rollbacks

6 Cevap php

Örneğin, aşağıdaki aramalar ile uzaktan API var:

getGroupCapacity(group)
setGroupCapacity(group, quantity)
getNumberOfItemsInGroup(group)
addItemToGroup(group, item)
deleteItemFromGroup(group, item)

The task is to add some item to some group. Groups have capacity. So first we should check if group is not full. If it is, increase capacity, then add item. Something like this (for example API is exposed with SOAP):

function add_item($group, $item) {
   $soap = new SoapClient(...);
   $capacity = $soap->getGroupCapacity($group);
   $itemsInGroup = $soap->getNumberOfItemsInGroup($group);
   if ($itemsInGroup == $capacity) {
       $soap->setGroupCapacity($group, $capacity + 1);
   }
   $soap->addItemToGroup($group, $item);
}

Şimdi ne (madde kötü oldu) addItemToGroup başarısız olursa? Biz grubun kapasitesini geri almak gerekir.

Tek bir işlemle ve tüm bu - Şimdi gruba 10 öğeler eklemek zorunda ve daha sonra kurulum bazı özelliklere sahip öğeler ekledi düşünün. Yani ortada bir yerde başarısız eğer önceki durumuna şeyi geri alma gerektiği anlamına gelir.

Bu IF adlı ve spagetti kod demet olmadan mümkün mü? (PHP) gibi işlemleri basitleştirmek olacak herhangi bir kitaplık, çerçeve, desen veya mimarlık karar?

UPD: SABUN sadece bir örnektir. Çözüm, hatta ham TCP herhangi bir hizmeti uygun olmalıdır. Sorunun ana noktası yatan işlemsel olmayan API ile işlem davranışlarını düzenlemek için nasıl.

UPD2: Ben bu sorun, tüm programlama dilleri oldukça aynıdır sanırım. Yani herhangi bir cevap, PHP değil, sadece bekliyoruz.

Şimdiden teşekkürler!

6 Cevap

Uzak hizmetler genellikle işlemlerini desteklemez. Ben PHP bilmiyorum, ama BPEL size Compensation olarak denilen bir şey var.

Tazminat, ya da zaten başarıyla tamamlayan iş süreci geri alma adımları, iş süreçlerinde en önemli kavramlardan biridir. Tazminat hedefi terk ediliyor, bir iş sürecinin bir parçası olarak gerçekleştirilmiştir önceki faaliyetlerin etkilerini tersine çevirmektir.

Belki benzer bir şey deneyebilirsiniz. Bazı if / else orada olacağım.

Uzak tarafta işlem mantığı koydu. setGroupCapacity ()) (addItemToGroup kapsüllü olmalıdır. Bu arayan hakkında rahatsız olmamalı, iç devlet, bir şeydir. Bu ile öğe ile öğesi ekleyebilir ve kolayca deleteItemFromGroup () ile bu gevşeyin.

Eğer bir düşük seviye API ile yaşamak gerekiyorsa o zaman geri alma eylemleri akışını izleme size güvenir.

PHP Exceptions

Size uygun durumlar atma sınıfları tek tek soap sorguları saklanması olabilir.

Bir kirli çözelti, bir istisna dizi oluşturmak için olacak ve elle eklersiniz QueryStatus = false veya QueryStatus = her adım için doğru ve önerilen işlem geçerli olup olmadığını denetleyecektir. Eğer öyleyse, bir nihai CommitTransaction yöntemini çağırın.

Teorik olarak, "WS-DeathStar" protokol ailesi, bununla tam yani WS-Transaction fırsatlar biridir. Ancak, PHP bu standardın herhangi uygulamaları (Gerçi bir PHP dev değilim) farkında değilim.

Sadece bir veritabanı gibi, işlem ve / veya kilitleme duyduğunuz gibi geliyor. müşteri kodu gibi bir şey okumak istiyorum:

function add_item($group, $item) {
   $soap = new SoapClient(...);
   $transaction = $soap->startTransaction();
   # or: 
   #   $lock = $soap->lockGroup($group, "w");
   # strictly to prevent duplication of the rest of the code: 
   #   $transaction = $lock;
   $capacity = $soap->getGroupCapacity($transaction, $group);
   $itemsInGroup = $soap->getNumberOfItemsInGroup($transaction, $group);
   if ($itemsInGroup == $capacity) {
       $soap->setGroupCapacity($transaction, $group, $capacity + 1);
   }
   $soap->addItemToGroup($transaction, $group, $item);
   $transaction->commit();
   # or: $lock->release();
}

Tabii ki, / işlemekle bırakmadan veya diğer istemciler gereksiz başarısız olmasına neden, çok kilit olanlar önce böyle olanlar bu kaza gibi istenmeyen davranış müşterilerine işlemek gerekir. Bu hareketsizlik ve maksimum zaman aşımları, ve müşteri başına kilit sayısı ile mümkündür.

Gregor Hohpe uzaktan hataları işlemek için çeşitli yaklaşımlar güzel bir özetini yazdı:

Your Coffee Shop Doesn’t Use Two-Phase Commit

Kısaca:

  • Write-off: hiçbir şey, ya da yapılan işi atın.
  • Retry: başarısız parçaları yeniden deneyin. Kolay Eğer hiçbir kötü etkisi ile aynı girişe sahip tekrar tekrar çalıştırmak olabilir ki, idempotent olmak için hizmet tasarımı eğer.
  • Compensating action: Eğer şimdiye kadar çalışmanızı geri sağlayan bir dengeleme hareketi ile bir hizmet sunmak.
  • Transaction coordinator: geleneksel iki fazlı işlemek. Teorik olarak, ideal bir uygulama içinde çekmek zor, orada adamcağız katman sürü.

Ancak, durumda, Uzak API taneli çok ince olabilir. Eğer gerçekten setGroupCapacity, ayrı bir hizmet olarak ihtiyacım var mı? Nasıl sadece sağlama konusunda addUserToGroup, ve hizmet içi herhangi gerekli kapasite artışı işlemek izin? Bu şekilde, tüm işlem tek bir servis çağrısı yer olabilir.

Geçerli API ayrıca eşzamanlılık sorunları ve yarış koşulları için açılır. Ne getNumberOfItemsInGroup ve setGroupCapacity çağrısı arasında, diğer bazı iplik bir kullanıcı eklemek için yönetir, eğer? Diğer iplik senin kapasite artışı "çaldı" çünkü istek başarısız olur.