|
|
@@ -22,7 +22,6 @@ import org.slf4j.Logger;
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
|
|
import java.time.Instant;
|
|
|
-import java.nio.charset.StandardCharsets;
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.HashSet;
|
|
|
import java.util.LinkedHashSet;
|
|
|
@@ -34,7 +33,6 @@ import java.util.concurrent.ExecutorService;
|
|
|
import java.util.concurrent.Executors;
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
|
-import java.util.zip.CRC32;
|
|
|
|
|
|
/**
|
|
|
* 统一转化同步:
|
|
|
@@ -48,6 +46,7 @@ public class ConversionSyncService {
|
|
|
private static final Logger log = LoggerFactory.getLogger(ConversionSyncService.class);
|
|
|
private static final int REALTIME_CONCURRENCY = 10;
|
|
|
private static final int BACKFILL_CONCURRENCY = 16;
|
|
|
+ private static final int DEDUCTION_WINDOW_SIZE = 100;
|
|
|
|
|
|
private final ConversionClient baiduClient;
|
|
|
private final RedisHotStore hotStore;
|
|
|
@@ -588,7 +587,23 @@ public class ConversionSyncService {
|
|
|
if (!isNewTrackingLink(task.tencentBid)) {
|
|
|
return false;
|
|
|
}
|
|
|
- return bucketOf(task) < deductionCountPerTen(deductionRate);
|
|
|
+ if (!hotStore.markConversionSeen(task.callbackKey)) {
|
|
|
+ log.info("[ConversionSync] 腾讯转化已见过,跳过扣量计数 | callbackKey={} | qk={} | accountId={}",
|
|
|
+ task.callbackKey, task.payment.getQk(), safe(task.tencentBid.getAccountId()));
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ long counter = hotStore.incrementDeductionCounter(
|
|
|
+ task.tencentBid.getAccountId(),
|
|
|
+ task.payment.getAct(),
|
|
|
+ resolveTrackingVersion(task.tencentBid),
|
|
|
+ task.payment.getDate()
|
|
|
+ );
|
|
|
+ int slot = deductionSlot(counter);
|
|
|
+ boolean deduct = slot < deductionRate;
|
|
|
+ log.info("[ConversionSync] 腾讯转化扣量判定 | qk={} | act={} | accountId={} | version={} | rate={} | counter={} | slot={} | callbackKey={} | deduct={}",
|
|
|
+ task.payment.getQk(), task.payment.getAct(), safe(task.tencentBid.getAccountId()),
|
|
|
+ resolveTrackingVersion(task.tencentBid), deductionRate, counter, slot, task.callbackKey, deduct);
|
|
|
+ return deduct;
|
|
|
}
|
|
|
|
|
|
private static boolean isNewTrackingLink(BidRecord bid) {
|
|
|
@@ -605,19 +620,6 @@ public class ConversionSyncService {
|
|
|
|| "v4".equalsIgnoreCase(version);
|
|
|
}
|
|
|
|
|
|
- private int bucketOf(CallbackTask task) {
|
|
|
- CRC32 crc32 = new CRC32();
|
|
|
- crc32.update(String.join("|",
|
|
|
- safe(task.tencentBid.getMedia()),
|
|
|
- safe(task.payment.getQk()),
|
|
|
- safe(task.payment.getDate()),
|
|
|
- safe(task.payment.getDeviceId()),
|
|
|
- safe(task.tencentBid.getTagId()),
|
|
|
- String.valueOf(task.payment.getAct()),
|
|
|
- safe(task.tencentActionType)).getBytes(StandardCharsets.UTF_8));
|
|
|
- return (int) (crc32.getValue() % 10);
|
|
|
- }
|
|
|
-
|
|
|
private MediaCallbackRecord buildDeductedCallbackRecord(CallbackTask task) {
|
|
|
MediaCallbackRecord record = new MediaCallbackRecord();
|
|
|
Instant now = Instant.now();
|
|
|
@@ -639,18 +641,15 @@ public class ConversionSyncService {
|
|
|
record.setTrackingVersion(resolveTrackingVersion(task.tencentBid));
|
|
|
record.setCreatedAt(now);
|
|
|
int deductionRate = resolveDeductionRate(task.tencentBid);
|
|
|
- log.info("[ConversionSync] 腾讯转化扣量 | qk={} | act={} | rate={} | tagId={} | bucket={} | callbackKey={}",
|
|
|
+ log.info("[ConversionSync] 腾讯转化扣量 | qk={} | act={} | rate={} | tagId={} | accountId={} | callbackKey={}",
|
|
|
task.payment.getQk(), task.payment.getAct(), deductionRate,
|
|
|
- task.tencentBid.getTagId(), bucketOf(task), task.callbackKey);
|
|
|
+ task.tencentBid.getTagId(), safe(task.tencentBid.getAccountId()), task.callbackKey);
|
|
|
return record;
|
|
|
}
|
|
|
|
|
|
- private int deductionCountPerTen(int deductionRate) {
|
|
|
- int count = deductionRate / 10;
|
|
|
- if (count > 10) {
|
|
|
- return 10;
|
|
|
- }
|
|
|
- return Math.max(count, 0);
|
|
|
+ private int deductionSlot(long counter) {
|
|
|
+ long normalized = Math.max(counter - 1L, 0L);
|
|
|
+ return (int) (normalized % DEDUCTION_WINDOW_SIZE);
|
|
|
}
|
|
|
|
|
|
private static String resolveTrackingVersion(BidRecord bid) {
|