TransactionHandler — Background Processing¶
Обзор¶
TransactionHandler — фоновый сервис для обработки транзакций, синхронизации с ВИНК и расчёта балансов. Работает на базе Quartz.NET планировщика.
Архитектура¶
graph TB
subgraph "TransactionHandler"
PROGRAM[Program.cs<br/>Entry Point]
STARTUP[Startup.cs<br/>DI Config]
QUARTZ[Quartz.NET<br/>Scheduler]
JOBS[Jobs<br/>5 min interval]
end
subgraph "Core Services"
FPTS[FinancePartTransactionService<br/>Transaction Processing]
TM[TransactionManager<br/>State Coordination]
JST[JobStatusTracker<br/>Health Monitor]
end
subgraph "External"
DB[(PostgreSQL)]
VINKS[VINK APIs]
MQ[RabbitMQ]
end
PROGRAM --> STARTUP --> QUARTZ --> JOBS --> FPTS --> DB
FPTS --> VINKS
JOBS --> TM
JOBS --> JST
FPTS --> MQ
Core Components¶
Program.cs¶
Точка входа с глобальной обработкой исключений:
// Global exception handling
AppDomain.CurrentDomain.UnhandledException += (sender, e) =>
{
if (e.ExceptionObject is OutOfMemoryException ||
e.ExceptionObject is InsufficientMemoryException)
{
// Log and restart
}
};
// Jobs registered in Production only
q.AddJobsTransactionHandler(); // FinanceTransactionCalculateJob
TransactionManager¶
Координатор операций через флаги состояния:
| Флаг | Описание |
|---|---|
IsSyncTransaction |
Синхронизация транзакций в процессе |
IsRecalculateTransaction |
Перерасчёт транзакций |
IsCalculateBalance |
Расчёт баланса |
IsReconciliationOfBalances |
Сверка балансов |
IsHourCheckBalance |
Ежечасная проверка баланса |
IsHavingBalanceActionNeedProcess |
Есть действия с балансами |
Проверки конкурентности¶
public bool CanCalculateBalance()
=> !IsReconciliationOfBalances && !IsHourCheckBalance;
public bool CanRecalculateTransaction()
=> !IsReconciliationOfBalances;
Жизненный цикл транзакции¶
stateDiagram-v2
[*] --> Received: External VINK API
Received --> Pending: FinanceTransaction.Create()
Pending --> Processing: NeedCalculate = true
Processing --> Validation: FinanceTransactionCalculateJob (5 min)
Validation --> Parts: Card & Contract valid
Validation --> Failed: No contract
Parts --> Pricing: PartTransactions()
Pricing --> Negative: Check balance
Pricing --> Normal: Balance OK
Negative --> Final: Negative pricing
Normal --> Final: Normal pricing
Final --> Done: NeedCalculate = false
Failed --> [*]
Done --> [*]
Типы частей транзакции¶
| Тип | Описание | Поток |
|---|---|---|
ВинкДистрибьютор |
VINK → Дистрибьютор | Fuel Vendor → Distributor |
ДистрибьюторПокупатель |
Дистрибьютор → Покупатель | Distributor → Customer |
ПокупательПокупатель |
Покупатель → Покупатель | Resale → Another Company |
Расчёт цены¶
graph TD
FT[FinanceTransaction] --> DISCOUNT[Get Discount from Contract]
DISCOUNT --> BALANCE{Balance Status}
BALANCE -->|Negative| NEG[Negative Pricing]
BALANCE -->|OK| CONDITION[Get Contract Condition]
CONDITION --> TEMPLATE[Apply Pricing Template]
TEMPLATE --> FINAL[Final Price = Base ± Discount/Markup]
NEG --> FINAL
Опции отрицательного баланса¶
- Процент reduction:
PercentDiscountForNegativeBalance - Рубль surcharge:
RubleForNegativeBalance - Stella price (без скидки):
PriceByStellaForNegativeBalance
Расписание задач¶
Основные задачи¶
| Задача | Интервал | Назначение |
|---|---|---|
FinanceTransactionCalculateJob |
5 мин | Расчёт транзакций |
ApiJob (GasStations) |
48 часов | Синхронизация АЗС |
ApiJob (Cards) |
2 часа | Синхронизация карт |
ApiJob (Balance) |
20 мин | Синхронизация балансов |
ApiJob (HistoryTransactions) |
35 мин | История транзакций |
BillingJob |
08:00, 20:00 | Сверка балансов |
CalculateBalanceActionsJob |
30 сек | Обработка действий |
Специфичные задачи ВИНК¶
Tatneft¶
| Задача | Интервал | Описание |
|---|---|---|
SyncTransactionTatneftJob |
1 мин | Синхронизация транзакций |
TatneftBlockJob |
1 мин | Блокировка карт |
TatneftLimitJob |
1 мин | Лимиты |
BalanceTatneftUpdateJob |
10 мин | Баланс |
TatneftFormationReportByMounthJob |
Ежедневно 02:00 | Месячные отчёты |
Gazprom¶
| Задача | Интервал | Описание |
|---|---|---|
GazpromCreateReportsJob |
Ежечасно | Ночные отчёты |
Health Monitoring¶
Health Check Endpoint¶
Response:
{
"status": "Healthy",
"checks": [
{
"name": "job_health",
"status": "Healthy",
"description": "FinanceTransactionCalculateJob running",
"data": {
"lastRun": "2026-01-05T01:45:00Z"
}
}
],
"totalDuration": 15.5
}
JobStatusTracker¶
Мониторинг выполнения задач:
- Последняя успешная executed
- Детекция failures
- Duration tracking
Отслеживание владельца карты¶
Система отслеживает изменения владельца карты во времени:
public int? GetCardOwnerIdAtDate(
int cardId,
DateTime localTransactionTime,
int timeZoneOffsetHours)
Это позволяет корректно атрибутировать транзакции при передаче карт между владельцами.
Конфигурация¶
Environment¶
| Окружение | Jobs Enabled |
|---|---|
| Development | ❌ Disabled |
| Test | ❌ Disabled |
| Production | ✅ Enabled |
Connection String¶
Troubleshooting¶
Транзакции застряли с NeedCalculate = true¶
Причина: У карты нет CurrentContractBalanceId
Решение: Убедитесь в корректной настройке баланса контракта
Некорректное ценообразование¶
Причина: Отсутствуют шаблоны цен топлива
Решение: Проверьте FuelPriceForTemplate и RegionDirectContractWithVendorDiscount
Дрейф баланса¶
Причина: Необработанные записи BalanceAction
Решение: Проверьте выполнение CalculateBalanceActionsJob
Связанная документация¶
- Data Access Layer — репозитории и API клиенты
- API интеграции — ВИНК интеграции