< Summary

Information
Class: OzonOrdersWeb.Observability.TriggerBodyHealingInterceptor
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Observability/TriggerBodyHealingInterceptor.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 28
Coverable lines: 28
Total lines: 71
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 13
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
CommandFailed(...)0%620%
CommandFailedAsync(...)0%620%
HealAsync()0%5670%
Truncate(...)0%620%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Observability/TriggerBodyHealingInterceptor.cs

#LineLine coverage
 1using System.Data.Common;
 2using Microsoft.EntityFrameworkCore.Diagnostics;
 3using Serilog;
 4using Services.DataServices.TriggerSelfHealing;
 5
 6namespace OzonOrdersWeb.Observability;
 7
 8/// <summary>
 9/// Ловит MariaDB 1711 («Unknown trigger has an error in its body») на командах EF и перезагружает
 10/// триггеры пострадавшей таблицы через <see cref="TriggerBodyErrorHealer"/>. Сама команда всё равно
 11/// падает — её повторяет MySqlRetryingExecutionStrategy (1711 добавлен в список ретраев), а после
 12/// перезагрузки триггера повтор проходит. Log.Error — чтобы лог-вотчер завёл issue: это сигнал,
 13/// что на сервере снова был lock-storm с KILL QUERY.
 14/// </summary>
 015public sealed class TriggerBodyHealingInterceptor(TriggerBodyErrorHealer healer) : DbCommandInterceptor
 16{
 17    public override void CommandFailed(DbCommand command, CommandErrorEventData eventData)
 18    {
 019        if (TriggerBodyErrorHealer.IsTriggerBodyError(eventData.Exception))
 020            HealAsync(command, eventData).GetAwaiter().GetResult();
 021    }
 22
 23    public override Task CommandFailedAsync(
 24        DbCommand command,
 25        CommandErrorEventData eventData,
 26        CancellationToken cancellationToken = default)
 27    {
 028        return TriggerBodyErrorHealer.IsTriggerBodyError(eventData.Exception)
 029            ? HealAsync(command, eventData)
 030            : Task.CompletedTask;
 31    }
 32
 33    private async Task HealAsync(DbCommand command, CommandErrorEventData eventData)
 34    {
 35        TriggerHealResult result;
 36        try
 37        {
 38            // Не завязываемся на отменённый токен упавшей команды: лечение должно дойти до конца.
 039            result = await healer.TryHealAsync(eventData.Exception, command.CommandText, CancellationToken.None);
 040        }
 041        catch (Exception ex)
 42        {
 043            Log.Error(ex, "Триггер сломан (MariaDB 1711), самолечение упало с исключением | context={Context}",
 044                eventData.Context?.GetType().Name);
 045            return;
 46        }
 47
 048        switch (result.Outcome)
 49        {
 50            case TriggerHealOutcome.Reloaded:
 051                Log.Error(
 052                    "Триггер таблицы {Table} сломан (MariaDB 1711 'Query was empty'), перезагружено триггеров: {Count}. 
 053                    result.Table, result.ReloadedTriggers, Truncate(command.CommandText));
 054                break;
 55            case TriggerHealOutcome.Failed:
 056                Log.Error(
 057                    "Триггер таблицы {Table} сломан (MariaDB 1711), перезагрузка не удалась: {Error}",
 058                    result.Table, result.Error);
 059                break;
 60            case TriggerHealOutcome.SkippedCooldown:
 061                Log.Warning("Триггер таблицы {Table}: повторный 1711 в окне cooldown, перезагрузка уже была", result.Tab
 062                break;
 63            case TriggerHealOutcome.UnknownTable:
 064                Log.Error("MariaDB 1711 на команде без распознанной таблицы, лечение пропущено: {Command}",
 065                    Truncate(command.CommandText));
 66                break;
 67        }
 068    }
 69
 070    private static string Truncate(string text) => text.Length <= 300 ? text : text[..300] + "…";
 71}