cash_loader
Кеш блокировок: BlockingCacheLoader
Назначение
BlockingCacheLoader
— это компонент (Spring Bean), который отвечает за загрузку и поддержание в памяти актуального набора блокировок для мгновенной проверки возможности движения ТМЦ по любым объектам (SKU, ячейка, контейнер и т.д.) без обращения к БД.
Как работает
-
Загрузка активных блокировок
- При старте приложения и далее периодически (
@Scheduled
) или по событию (@EventListener
) из таблицblocking_doc
иblocking_doc_item
загружаются все записи со статусомACTIVE
. - Каждая строка документа преобразуется в пару (
BlockingKey
, набор операций).
- При старте приложения и далее периодически (
-
Структура кеша
-
Используется потокобезопасная структура:
ConcurrentHashMap<BlockingKey, Set<BlockedOperation>>
-
Где
BlockingKey
— комбинация типа объекта (BlockingObjectType
) и его идентификатора (referenceId
).
-
-
Публичный интерфейс
-
Проверка блокировки:
public boolean isBlocked(BlockingObjectType type, String referenceId, BlockedOperation op)
-
Возвращает true, если операция заблокирована для объекта.
-
-
Обновление кеша
- Кеш обновляется либо по расписанию, либо после событий изменения документов (
BlockingDocChangedEvent
). - После обновления старые данные полностью заменяются новыми (atomic replace).
- Кеш обновляется либо по расписанию, либо после событий изменения документов (
Пример реализации
@Service
public class BlockingCacheLoader {
private final BlockingDocRepository docRepo;
private final ConcurrentHashMap<BlockingKey, Set<BlockedOperation>> cache = new ConcurrentHashMap<>();
public boolean isBlocked(BlockingObjectType type, String refId, BlockedOperation op) {
var key = new BlockingKey(type, refId);
return cache.getOrDefault(key, Set.of()).contains(op);
}
@PostConstruct
@Scheduled(fixedDelay = 60000) // обновлять каждые 60 сек
public void reload() {
var newCache = new ConcurrentHashMap<BlockingKey, Set<BlockedOperation>>();
List<BlockingDocEntity> docs = docRepo.findAllActive();
for (var doc : docs) {
for (var item : doc.getItems()) {
var key = new BlockingKey(item.getType(), item.getReferenceId());
newCache.computeIfAbsent(key, k -> new HashSet<>()).addAll(item.getOperations());
}
}
cache.clear();
cache.putAll(newCache);
}
@EventListener
public void onBlockingDocChanged(BlockingDocChangedEvent event) {
reload();
}
}