|
@@ -9,6 +9,7 @@ import com.adx.tencent.conversionsync.ConversionSyncService;
|
|
|
import com.adx.tencent.conversionsync.RetryService;
|
|
import com.adx.tencent.conversionsync.RetryService;
|
|
|
import com.adx.tencent.httpapi.MediaPlacement;
|
|
import com.adx.tencent.httpapi.MediaPlacement;
|
|
|
import com.adx.tencent.leader.LeaderElection;
|
|
import com.adx.tencent.leader.LeaderElection;
|
|
|
|
|
+import com.adx.tencent.tagsync.TagEventSyncService;
|
|
|
import com.adx.tencent.tencent.TencentClient;
|
|
import com.adx.tencent.tencent.TencentClient;
|
|
|
import com.adx.tencent.storage.RedisHotStore;
|
|
import com.adx.tencent.storage.RedisHotStore;
|
|
|
import com.adx.tencent.storage.RedisLock;
|
|
import com.adx.tencent.storage.RedisLock;
|
|
@@ -34,6 +35,7 @@ import org.springframework.stereotype.Component;
|
|
|
import org.springframework.lang.Nullable;
|
|
import org.springframework.lang.Nullable;
|
|
|
|
|
|
|
|
import javax.sql.DataSource;
|
|
import javax.sql.DataSource;
|
|
|
|
|
+import java.time.Duration;
|
|
|
import java.util.HashMap;
|
|
import java.util.HashMap;
|
|
|
import java.util.List;
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
import java.util.Map;
|
|
@@ -203,6 +205,16 @@ public class AppConfiguration {
|
|
|
return new RetryService(coldStore, tencentClient, props.getCallbackRetryLimit());
|
|
return new RetryService(coldStore, tencentClient, props.getCallbackRetryLimit());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ @Bean
|
|
|
|
|
+ public TagEventSyncService tagEventSyncService(@Nullable TiDBColdStore coldStore,
|
|
|
|
|
+ StringRedisTemplate redisTemplate) {
|
|
|
|
|
+ if (coldStore == null) return null;
|
|
|
|
|
+ // TTL 取同步间隔的 3 倍,避免表中已删除的 tag 在 Redis 长期残留
|
|
|
|
|
+ Duration ttl = props.getTagEventSyncInterval().multipliedBy(3);
|
|
|
|
|
+ return new TagEventSyncService(coldStore, redisTemplate,
|
|
|
|
|
+ props.getTagEventSyncRedisPrefix(), ttl);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// ─── ColdWorker ─────────────────────────────────────────────────────────
|
|
// ─── ColdWorker ─────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
@Bean
|
|
@Bean
|
|
@@ -254,6 +266,7 @@ public class AppConfiguration {
|
|
|
@Autowired(required = false) private ColdWorker coldWorker;
|
|
@Autowired(required = false) private ColdWorker coldWorker;
|
|
|
@Autowired(required = false) private ConversionSyncRunner conversionSyncRunner;
|
|
@Autowired(required = false) private ConversionSyncRunner conversionSyncRunner;
|
|
|
@Autowired(required = false) private RetryService retryService;
|
|
@Autowired(required = false) private RetryService retryService;
|
|
|
|
|
+ @Autowired(required = false) private TagEventSyncService tagEventSyncService;
|
|
|
@Autowired(required = false) private LeaderElection leaderElection;
|
|
@Autowired(required = false) private LeaderElection leaderElection;
|
|
|
|
|
|
|
|
private final AtomicBoolean stopped = new AtomicBoolean(false);
|
|
private final AtomicBoolean stopped = new AtomicBoolean(false);
|
|
@@ -323,6 +336,28 @@ public class AppConfiguration {
|
|
|
taskLog.warn("Callback retry NOT started: retryService={}, enabled={}",
|
|
taskLog.warn("Callback retry NOT started: retryService={}, enabled={}",
|
|
|
retryService != null, props.isCallbackRetryEnabled());
|
|
retryService != null, props.isCallbackRetryEnabled());
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ // 广告位回传方式同步
|
|
|
|
|
+ if (tagEventSyncService != null && props.isTagEventSyncEnabled()) {
|
|
|
|
|
+ if (props.isSkipLeaderElection()) {
|
|
|
|
|
+ executor.submit(() -> runTagEventSync(() -> stopped.get()));
|
|
|
|
|
+ taskLog.info("Tag event sync started (skip leader election)");
|
|
|
|
|
+ } else if (leaderElection != null) {
|
|
|
|
|
+ executor.submit(() ->
|
|
|
|
|
+ leaderElection.run(
|
|
|
|
|
+ "adx:lock:tencent:tag-event-sync",
|
|
|
|
|
+ props.getTaskLockTtl(), props.getTaskLockRenewInterval(), props.getTaskLockRetryInterval(),
|
|
|
|
|
+ stopped::get,
|
|
|
|
|
+ (jobStop) -> runTagEventSync(jobStop),
|
|
|
|
|
+ e -> taskLog.error("tencent tag event sync leader: {}", e.getMessage(), e)
|
|
|
|
|
+ )
|
|
|
|
|
+ );
|
|
|
|
|
+ taskLog.info("Tag event sync leader election started");
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ taskLog.warn("Tag event sync NOT started: service={}, enabled={}",
|
|
|
|
|
+ tagEventSyncService != null, props.isTagEventSyncEnabled());
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private void runConversionSync(LeaderElection.StopSignal jobStop) {
|
|
private void runConversionSync(LeaderElection.StopSignal jobStop) {
|
|
@@ -359,6 +394,21 @@ public class AppConfiguration {
|
|
|
taskLog.info("[CallbackRetry] task stopped");
|
|
taskLog.info("[CallbackRetry] task stopped");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ private void runTagEventSync(LeaderElection.StopSignal jobStop) {
|
|
|
|
|
+ long intervalMs = props.getTagEventSyncInterval().toMillis();
|
|
|
|
|
+ taskLog.info("[TagEventSync] task started, interval={}ms", intervalMs);
|
|
|
|
|
+ while (!jobStop.isStopped()) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ int n = tagEventSyncService.syncOnce();
|
|
|
|
|
+ taskLog.info("[TagEventSync] done: synced={}", n);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ taskLog.error("[TagEventSync] error: {}", e.getMessage(), e);
|
|
|
|
|
+ }
|
|
|
|
|
+ sleepResponsive(intervalMs, jobStop);
|
|
|
|
|
+ }
|
|
|
|
|
+ taskLog.info("[TagEventSync] task stopped");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private static void sleepResponsive(long ms, LeaderElection.StopSignal jobStop) {
|
|
private static void sleepResponsive(long ms, LeaderElection.StopSignal jobStop) {
|
|
|
long deadline = System.currentTimeMillis() + ms;
|
|
long deadline = System.currentTimeMillis() + ms;
|
|
|
while (!jobStop.isStopped()) {
|
|
while (!jobStop.isStopped()) {
|