package jnpf.base.service.impl; import jnpf.base.service.LoginSessionService; import jnpf.config.ConfigValueUtil; import jnpf.database.util.DynamicDataSourceUtil; import jnpf.database.util.TenantDataSourceUtil; import jnpf.util.DateUtil; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import java.util.Collections; import java.util.Set; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; /** * Closes sessions after their last synchronized token expiry time. */ @Component @Slf4j @RequiredArgsConstructor public class LoginSessionExpirationWorker implements InitializingBean, DisposableBean { private static final String TENANT_REGISTRY_KEY = "jnpf:login-session:tenants"; private final LoginSessionService loginSessionService; private final ConfigValueUtil configValueUtil; private final RedisTemplate redisTemplate; private ScheduledExecutorService executor; @Override public void afterPropertiesSet() { ThreadFactory factory = runnable -> { Thread thread = new Thread(runnable, "login-session-expiration"); thread.setDaemon(true); return thread; }; executor = Executors.newSingleThreadScheduledExecutor(factory); executor.scheduleWithFixedDelay(this::closeExpired, 60, 60, TimeUnit.SECONDS); } private void closeExpired() { if (!configValueUtil.isMultiTenancy()) { closeCurrentTenant(); return; } Set tenantIds = redisTemplate.opsForSet().members(TENANT_REGISTRY_KEY); for (Object tenantId : tenantIds == null ? Collections.emptySet() : tenantIds) { try { TenantDataSourceUtil.switchTenant(String.valueOf(tenantId)); closeCurrentTenant(); } catch (Exception e) { log.warn("登录会话超时回收失败,tenantId: {}", tenantId, e); } finally { DynamicDataSourceUtil.clearSwitchDataSource(); } } } private void closeCurrentTenant() { try { loginSessionService.closeExpired(DateUtil.dateAddMinutes(DateUtil.getNowDate(), -2), 200); } catch (Exception e) { log.warn("登录会话超时回收失败", e); } } @Override public void destroy() { if (executor != null) { executor.shutdownNow(); } } }