Skip to content

Task 3-1: Dynamic Queue Re-registration at Runtime

Phase: 3 - Dynamic Queue Priority: Medium Module: batch Depends on: Không có Blocks: task-3-2 Reference: docs/BountyHunter-Backend/details/feature-game-room-management/SPEC.md

Background

Khi admin tạo machine mới hoặc game booth setting mới, cần restart toàn bộ batch service để ProgrammaticEndpointRegistration đăng ký listener mới. Gây downtime không cần thiết.

Tasks

File: batch/jms/register_destination/ProgrammaticEndpointRegistration.java

DI Note: ProgrammaticEndpointRegistration cần inject machineRepository để query database, và JmsListenerEndpointRegistrar (hoặc JmsListenerEndpointRegistry) để đăng ký listener mới dynamically. Kiểm tra class hiện tại xem đã có những dependencies nào được inject.

registeredMachineIds nên là ConcurrentHashSet (hoặc Collections.synchronizedSet(new HashSet<>())) để thread-safe với @Scheduled.

  • [ ] Thêm internal tracking sets vào class:

    // Thread-safe sets để track registered IDs
    private final Set<String> registeredMachineIds = Collections.synchronizedSet(new HashSet<>());
    private final Set<String> registeredSettingIds = Collections.synchronizedSet(new HashSet<>());
    

  • [ ] Extract logic đăng ký listener thành public method — Clarification: method này phải gọi được từ bên ngoài class (e.g., từ admin API hoặc scheduler) và phải idempotent (gọi nhiều lần với cùng ID không gây lỗi):

    public void registerMachineListener(String machineId) {
        // Di chuyển logic đăng ký listener cho machine vào đây
        // ...existing registration logic...
    }
    
    public void registerSettingListeners(String settingId) {
        // Di chuyển logic đăng ký listener cho setting vào đây
        // ...existing registration logic...
    }
    

  • [ ] Populate registeredMachineIds / registeredSettingIds khi @PostConstruct để phản ánh trạng thái ban đầu

  • [ ] Thêm scheduled polling check:

    // Clarification: machineRepository.findAllActiveMachineIds() phải return chỉ các machine đang active
    // (không phải tất cả, kể cả deleted/inactive)
    @Scheduled(fixedDelay = 60000)  // poll mỗi 60 giây
    public void checkForNewMachines() {
        Set<String> allMachineIds = machineRepository.findAllActiveMachineIds();
        allMachineIds.stream()
            .filter(id -> !registeredMachineIds.contains(id))
            .forEach(newId -> {
                registerMachineListener(newId);
                registeredMachineIds.add(newId);
                LOGGER.info("[DYNAMIC_QUEUE] Auto-registered new machine listener: {}", newId);
            });
    }
    

  • [ ] Thêm @Scheduled tương tự cho settings nếu machineRepository.findAllActiveMachineIds() pattern phù hợp

Verification / Acceptance Criteria

  • [ ] Thêm machine mới vào database → trong vòng 60 giây, listener tương ứng được đăng ký mà không cần restart
  • [ ] Log [DYNAMIC_QUEUE] Auto-registered new machine listener: {id} xuất hiện khi có machine mới
  • [ ] Gọi registerMachineListener(id) 2 lần với cùng ID → không đăng ký duplicate listener (idempotent)
  • [ ] registeredMachineIds được populate đầy đủ khi application start (không bị trống sau restart)
  • [ ] Concurrent access vào registeredMachineIds từ scheduler không gây ConcurrentModificationException
  • [ ] checkForNewMachines() không throw exception khi database không có machine mới
  • [ ] Task-3-2 (JmsListenerHealthIndicator) có thể thấy listeners được đăng ký dynamically

Files to Modify

  • batch/jms/register_destination/ProgrammaticEndpointRegistration.java