feat(webhook): retry delivery — POST /deliveries/{id}/retry + UI кнопка
Раньше для replay'а failed/DLQ delivery нужно было либо ждать
backoff schedule (до 24h), либо лезть в БД и руками сбрасывать
attempt_count + dlq_at. Теперь admin замечает failed delivery в
UI, фиксит receiver (cert renewal, URL update), кликает 'повторить'
— dispatcher подхватит на следующем sendTick.
Backend:
- POST /api/v1/admin/webhooks/deliveries/{id}/retry
- RBAC: RESTRICTED (можно spam'ить receiver = destructive)
- Использует existing WebhookDelivery.resetDlq() — атомарно
status=retrying, attemptCount=0, dlqAt=null, nextAttemptAt=now
UI:
- Колонка 'Действия' в delivery history таблице (на webhook detail page)
- IconButton 'Повторить' показывается только для status=dlq|retrying
(delivered/pending не имеет смысла retry'ить)
- Confirm dialog объясняет что receiver получит payload снова
- onSuccess invalidate ['webhooks','deliveries'] + ['webhooks','dlq']
Tests: 75 admin-ui passed, rest-api compiles clean. Логика
resetDlq() уже покрыта unit tests в WebhookDeliveryTest.
This commit is contained in:
@@ -6,6 +6,7 @@ import {
|
||||
type CreateWebhookSubscriptionRequest,
|
||||
type DictionaryDetail,
|
||||
type RecordResponse,
|
||||
type WebhookDelivery,
|
||||
type WebhookSubscription,
|
||||
} from './client'
|
||||
|
||||
@@ -164,3 +165,29 @@ export const useRotateWebhookSecret = () => {
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Replay delivery из DLQ или retrying — backend сбрасывает attemptCount=0,
|
||||
* dlqAt=null, status=retrying. Dispatcher подхватит на следующем sendTick.
|
||||
*
|
||||
* Use case: оператор fixed receiver URL/cert, хочет replay'нуть failed
|
||||
* delivery без ожидания TTL bypass'а.
|
||||
*/
|
||||
export const useRetryWebhookDelivery = () => {
|
||||
const qc = useQueryClient()
|
||||
return useMutation({
|
||||
mutationFn: async (deliveryId: number): Promise<WebhookDelivery> => {
|
||||
const { data } = await apiClient.post<WebhookDelivery>(
|
||||
`/admin/webhooks/deliveries/${deliveryId}/retry`,
|
||||
)
|
||||
return data
|
||||
},
|
||||
onSuccess: () => {
|
||||
// Invalidate всё что показывает delivery rows: detail page deliveries,
|
||||
// global DLQ list. Cheaper чем targeted invalidation т.к. delivery
|
||||
// counts маленькие.
|
||||
qc.invalidateQueries({ queryKey: ['webhooks', 'deliveries'] })
|
||||
qc.invalidateQueries({ queryKey: ['webhooks', 'dlq'] })
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user