Se o projeto foi além do escopo da máquina local, provavelmente você precisará se integrar a alguns sistemas de terceiros.
Quero considerar o caso em que o sistema externo mencionado deseja receber notificações de quaisquer alterações em nosso sistema. Por exemplo, atualizando um catálogo de produtos.
Tarefa
Existe uma plataforma de negociação que fornece acesso à sua base de produtos por meio de serviços WEB. Os parceiros do site desejam saber sobre alterações no banco de dados o mais rápido possível.
Opção de solução
Conhecemos todos os nossos parceiros, podemos solicitar documentação para seu software.
Você pode implementar o trabalho com a API de nossos parceiros e, ao alterar o catálogo de produtos, notificá-los diretamente.
Com essa abordagem, cada novo cliente precisará ser conectado individualmente. Se o parceiro alterou algo no software, serão necessários recursos para restaurar a funcionalidade. Em geral, despesas adicionais e uma zona extra de responsabilidade.
Eu realmente não quero estabelecer laços tão estreitos. Portanto, faremos o seguinte.
Vamos tomar o padrão de "observador" como base. Permita que nossos colegas se inscrevam em eventos e recebam as notificações de que precisam.
Implementação
Os registros de assinatura devem ser mantidos em algum lugar. O tipo de armazenamento permanecerá na consciência do desenvolvedor. Considere o que precisa ser armazenado.
- Evento. Pode haver muitos tipos de eventos e, para não enviar alertas a todos, você precisa saber quem se inscreveu no quê.
- URL. . HTTP- URL. , .
- . , ( , , ). , . - . .
, PHP.
, POST- URL. , b2b.api.my-soft.ru/event-subscription. URL event( ).
( Laravel):
public function subscribe()
{
$request = $this->getRequest();
$eventName = $request->input('event');
$url = $request->input('callback');
$validator = \Validator::make([
'url' => $url,
'event' => $eventName
], [
'url' => 'url|required',
'event' => 'required'
]);
if ($validator->fails()) {
throw new BadRequestHttpException($validator->errors()->first());
}
$repository = $this->getRepository();
if (!$repository->eventAvailable($eventName)) {
throw new BadRequestHttpException(trans('api.error.eventSubscription.wrongEvent'));
}
if (!$repository->canAddEvent($eventName)) {
throw new BadRequestHttpException(trans('api.error.eventSubscription.maxCallbacks'));
}
$model = $repository->createModel([
'client_id' => $request->attributes->get('client')->id,
'event' => $eventName,
'url' => $url
]);
if ($repository->save($model)) {
return $this->response($model);
}
throw new \Exception();
}
:
.
. , . , .. . .
, , .
.
, , . , , .
, . .
$subscribersRepository->with(['event' => $event->getEventName()])->getActive()->each(function ($model) use ($event) {
$this->dispatch(new \Commands\RemoteCallback(
$model->id,
$model->url,
$event->getData()->toArray()
));
});
.
RemoteCallback :
public function handle(EventSubscriptionRepository $subscriptionRepository)
{
$client = new \Guzzle\Http\Client();
$res = $client->post($this->url, [], $this->data, ['connect_timeout' => 3, 'timeout' => 3]);
try {
if ($res->send()->getStatusCode() !== 200) {
throw new \Exception();
}
$subscriptionRepository->dropErrors($this->subscriptionId);
} catch (\Exception $e) {
$subscriptionRepository->incrementError($this->subscriptionId);
}
}
. POST- URL. , , .
. . HTTP != 200, . , 3 3 . , .
Durante o processamento de uma solicitação de assinatura, a possibilidade disso é verificada (método canAddEvent). Pode ser qualquer coisa, mas no meu caso o limite do número de ouvintes é verificado. Não mais que 3 para cada tipo de evento.
Além disso, é claro, é necessária autorização para trabalhar com esses métodos de API.
É basicamente isso. A opção mais simples é descrita. Se necessário, você pode adicionar suporte para conexões SOAP ou soquete ou algo assim. E você precisa reenviar a mensagem se a resposta não tiver sido bem-sucedida.