Erros e Isolamento de Falhas¶
Esta página detalha a direção arquitetural esperada pelo ADR-0009.
O objetivo é separar com clareza:
- falha lateral: pode ser isolada e logada;
- falha obrigatória da operação: deve falhar junto com o fluxo principal;
- boundary HTTP: converte erro para resposta pública adequada;
- boot/lifecycle: isola falhas por fronteira.
Regra principal¶
O framework isola a falha quando a reação é lateral e o sistema pode continuar sem comprometer a verdade da operação.
Quando a parte que falha é obrigatória, a falha deve acompanhar o fluxo principal.
Reação lateral: pode falhar isoladamente¶
Exemplo educacional:
<?php
final class send_order_webhook_listener
{
public function __invoke(
\local_middag\extensions\ecommerce\signal\order_processed_signal $signal
): void {
try {
// integração externa derivada
} catch (\RuntimeException $exception) {
debug::trace_exception($exception);
}
}
}
Se o webhook falhar, o pedido não deve “desprocessar”.
Parte obrigatória da operação: não pode falhar isoladamente¶
Exemplo educacional:
<?php
final class audited_status_updater
{
public function __construct(
private repository_interface $repository,
private item_service $item_service,
private audit_writer_interface $audit_writer,
private revision_writer_interface $revision_writer,
) {}
public function update(int $item_id, string $status): void
{
$this->repository->begin();
try {
$this->item_service->update_status($item_id, $status);
$this->revision_writer->capture($item_id, ['status' => $status]);
$this->audit_writer->record(subject_id: $item_id, diff: [
'status' => ['old' => 'draft', 'new' => $status],
]);
$this->repository->commit();
} catch (\Throwable $exception) {
$this->repository->rollback();
throw $exception;
}
}
}
Aqui audit e revision fazem parte da verdade da operação. Se falharem, a operação falha também.
Boundary HTTP¶
Controller não deve transformar toda exceção em silêncio local. O boundary HTTP decide a resposta pública.
Exemplo educacional:
<?php
final class course_api_controller extends base_api_controller
{
public function save(): Response
{
$this->service->save();
return $this->json_response(['status' => 'ok']);
}
}
Se save() falhar, a exceção sobe para o HTTP kernel, que decide status code e payload público.
Boot de extension¶
Falha de uma extension não deve derrubar as demais.
Exemplo educacional:
<?php
try {
$extension->boot();
} catch (\Throwable $exception) {
debug::trace_exception($exception);
}
Validação depende do boundary¶
Em formulário ou API, validação pode virar resposta estruturada.
Exemplo educacional:
<?php
return $this->json_response([
'error' => 'validation_failed',
'messages' => ['name' => 'Campo obrigatório'],
], 422);
Em serviço interno, a mesma invalidez pode continuar sendo exceção.
O que não fazer¶
- não capturar erro crítico só para “seguir o fluxo”;
- não usar listener, hook ou bridge para esconder dependência obrigatória;
- não capturar e silenciar
Throwablegenericamente sem contexto; - não expor detalhes internos em resposta pública fora de modo debug.