yumeng 17 часов назад
Родитель
Сommit
decae34e15

+ 65 - 7
pom.xml

@@ -4,13 +4,6 @@
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
 
-    <parent>
-        <groupId>org.springframework.boot</groupId>
-        <artifactId>spring-boot-starter-parent</artifactId>
-        <version>3.2.5</version>
-        <relativePath/>
-    </parent>
-
     <groupId>com.adx</groupId>
     <artifactId>adx-tracking</artifactId>
     <version>1.0.0</version>
@@ -19,8 +12,48 @@
 
     <properties>
         <java.version>17</java.version>
+        <maven.compiler.source>${java.version}</maven.compiler.source>
+        <maven.compiler.target>${java.version}</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <spring-boot.version>3.2.5</spring-boot.version>
     </properties>
 
+    <profiles>
+        <profile>
+            <id>dev</id>
+            <activation>
+                <activeByDefault>true</activeByDefault>
+            </activation>
+            <properties>
+                <profileActive>dev</profileActive>
+            </properties>
+        </profile>
+        <profile>
+            <id>prod</id>
+            <properties>
+                <profileActive>prod</profileActive>
+            </properties>
+        </profile>
+        <profile>
+            <id>test</id>
+            <properties>
+                <profileActive>test</profileActive>
+            </properties>
+        </profile>
+    </profiles>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-dependencies</artifactId>
+                <version>${spring-boot.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
     <dependencies>
         <!-- Spring Web (REST API) -->
         <dependency>
@@ -66,10 +99,35 @@
     </dependencies>
 
     <build>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+                <filtering>true</filtering>
+            </resource>
+        </resources>
         <plugins>
             <plugin>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>${spring-boot.version}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-resources-plugin</artifactId>
+                <version>3.3.1</version>
+                <configuration>
+                    <delimiters>
+                        <delimiter>@</delimiter>
+                    </delimiters>
+                    <useDefaultDelimiters>false</useDefaultDelimiters>
+                </configuration>
             </plugin>
         </plugins>
     </build>

+ 9 - 0
src/main/java/com/adx/tracking/conversionsync/ConversionSyncService.java

@@ -47,14 +47,23 @@ public class ConversionSyncService {
         if (query.getPageSize() <= 0) query.setPageSize(1);
 
         SyncResult result = new SyncResult();
+        int maxPages = 100; // 安全上限,防止死循环
         for (int page = query.getPageSize(); ; page++) {
             query.setPageSize(page);
+            log.info("[ConversionSync] fetching page={}", page);
             ConversionResponse response = baiduClient.queryPayments(query);
             List<PaymentInfo> data = response.getData();
+            int dataSize = data != null ? data.size() : 0;
+            log.info("[ConversionSync] page={} returned {} records, responsePageSize={}",
+                    page, dataSize, response.getPageSize());
             if (data != null) {
                 processPayments(data, result);
             }
             if (response.getPageSize() <= page) break;
+            if (page >= maxPages) {
+                log.warn("[ConversionSync] reached max page limit ({}), stopping", maxPages);
+                break;
+            }
         }
         return result;
     }

+ 23 - 1
src/main/java/com/adx/tracking/media/kuaishou/KuaishouClient.java

@@ -4,6 +4,9 @@ import com.adx.tracking.baidu.model.PaymentInfo;
 import com.adx.tracking.storage.model.BidRecord;
 import com.adx.tracking.storage.model.MediaCallbackRecord;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URI;
@@ -13,6 +16,7 @@ import java.net.http.HttpClient;
 import java.net.http.HttpRequest;
 import java.net.http.HttpResponse;
 import java.nio.charset.StandardCharsets;
+import java.time.Duration;
 import java.time.Instant;
 import java.util.*;
 
@@ -25,13 +29,17 @@ import java.util.*;
  */
 public class KuaishouClient {
 
+    private static final Logger log = LoggerFactory.getLogger(KuaishouClient.class);
+
     private final HttpClient httpClient;
     private final Map<Integer, Integer> actMap;        // baiduAct -> kuaishouEventType
     private final Map<Integer, List<Integer>> extraActMap; // baiduAct -> [extra kuaishouEventTypes]
 
     public KuaishouClient(Map<Integer, Integer> actMapOverride,
                           Map<Integer, List<Integer>> extraActMap) {
-        this.httpClient = HttpClient.newHttpClient();
+        this.httpClient = HttpClient.newBuilder()
+                .connectTimeout(Duration.ofSeconds(10))
+                .build();
         // 从默认表开始,再用配置覆盖
         Map<Integer, Integer> merged = new HashMap<>(defaultActMap());
         if (actMapOverride != null) merged.putAll(actMapOverride);
@@ -96,9 +104,12 @@ public class KuaishouClient {
         record.setCallbackUrl(reportUrl);
 
         try {
+            log.info("[Kuaishou] sending callback: qk={}, eventType={}, url={}",
+                    payment.getQk(), eventType, truncate(reportUrl, 200));
             HttpRequest request = HttpRequest.newBuilder()
                     .uri(URI.create(reportUrl))
                     .GET()
+                    .timeout(Duration.ofSeconds(15))
                     .build();
             HttpResponse<byte[]> response = httpClient.send(request, HttpResponse.BodyHandlers.ofByteArray());
             int status = response.statusCode();
@@ -106,10 +117,14 @@ public class KuaishouClient {
             record.setStatus(status);
             record.setOk(status >= 200 && status < 300);
             record.setResponseBody(body);
+            log.info("[Kuaishou] callback result: qk={}, eventType={}, status={}, ok={}",
+                    payment.getQk(), eventType, status, record.isOk());
         } catch (Exception e) {
             // 对应 Go:即使 HTTP 请求失败也返回 record(ErrorMessage 已设置),不抛异常
             record.setOk(false);
             record.setErrorMessage(e.getMessage());
+            log.warn("[Kuaishou] callback failed: qk={}, eventType={}, error={}",
+                    payment.getQk(), eventType, e.getMessage());
         }
         return record;
     }
@@ -124,6 +139,7 @@ public class KuaishouClient {
         HttpRequest request = HttpRequest.newBuilder()
                 .uri(URI.create(original.getCallbackUrl()))
                 .GET()
+                .timeout(Duration.ofSeconds(15))
                 .build();
 
         MediaCallbackRecord retry = copyRecord(original);
@@ -131,15 +147,21 @@ public class KuaishouClient {
         retry.setCreatedAt(Instant.now());
 
         try {
+            log.info("[Kuaishou] retrying callback: dedupeKey={}, attempt={}, url={}",
+                    original.getDedupeKey(), retry.getAttempt(), truncate(original.getCallbackUrl(), 200));
             HttpResponse<byte[]> response = httpClient.send(request, HttpResponse.BodyHandlers.ofByteArray());
             int status = response.statusCode();
             retry.setStatus(status);
             retry.setOk(status >= 200 && status < 300);
             retry.setResponseBody(truncate(new String(response.body()), 4096));
             retry.setErrorMessage(null);
+            log.info("[Kuaishou] retry result: dedupeKey={}, status={}, ok={}",
+                    original.getDedupeKey(), status, retry.isOk());
         } catch (IOException | InterruptedException e) {
             retry.setOk(false);
             retry.setErrorMessage(e.getMessage());
+            log.warn("[Kuaishou] retry failed: dedupeKey={}, error={}",
+                    original.getDedupeKey(), e.getMessage());
             throw e;
         }
         return retry;

+ 34 - 0
src/main/resources/application-dev.yml

@@ -0,0 +1,34 @@
+# ============================================================
+# 开发环境配置 (dev)
+# ============================================================
+
+adx:
+  # --- Baidu ADX ---
+  baidu-adx-endpoint: "http://adsp.baidu.com/jbssp"
+  baidu-conversion-base-url: "https://media-interact-test.baidu.com"
+  baidu-customer-name: dingzhaoming111
+  baidu-secret: gk780scz3oi2
+
+  # --- Redis ---
+  redis-addr: "cq-crs-47p6pmwo.sql.tencentcdb.com:28036"
+  redis-username: hcst
+  redis-password: "hcst@2026qwe.."
+  redis-db: 0
+
+  # --- TiDB/MySQL ---
+  tidb-url: "jdbc:mysql://139.186.172.149:3390/adx_proxy?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&connectTimeout=5000&socketTimeout=30000"
+  tidb-username: hcst
+  tidb-password: "hcst@2025"
+
+  # --- Task (skip leader election for local dev) ---
+  skip-leader-election: true
+
+  # --- Conversion Sync ---
+  conversion-sync-enabled: true
+  conversion-sync-interval: 5s
+  conversion-sync-date-offset-days: 0
+  conversion-sync-page-size: 1
+
+  # --- Callback Retry ---
+  callback-retry-enabled: true
+  callback-retry-interval: 300s

+ 34 - 0
src/main/resources/application-prod.yml

@@ -0,0 +1,34 @@
+# ============================================================
+# 生产环境配置 (prod)
+# ============================================================
+
+adx:
+  # --- Baidu ADX ---
+  baidu-adx-endpoint: "http://adsp.baidu.com/jbssp"
+  baidu-conversion-base-url: "https://media-interact.baidu.com"
+  baidu-customer-name: dingzhaoming111
+  baidu-secret: gk780scz3oi2
+
+  # --- Redis ---
+  redis-addr: "cq-crs-47p6pmwo.sql.tencentcdb.com:28036"
+  redis-username: hcst
+  redis-password: "hcst@2026qwe.."
+  redis-db: 0
+
+  # --- TiDB/MySQL ---
+  tidb-url: "jdbc:mysql://139.186.172.149:3390/adx_proxy?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&connectTimeout=5000&socketTimeout=30000"
+  tidb-username: hcst
+  tidb-password: "hcst@2025"
+
+  # --- Task ---
+  skip-leader-election: false
+
+  # --- Conversion Sync ---
+  conversion-sync-enabled: true
+  conversion-sync-interval: 5s
+  conversion-sync-date-offset-days: 0
+  conversion-sync-page-size: 1
+
+  # --- Callback Retry ---
+  callback-retry-enabled: true
+  callback-retry-interval: 300s

+ 34 - 0
src/main/resources/application-test.yml

@@ -0,0 +1,34 @@
+# ============================================================
+# 测试环境配置 (test)
+# ============================================================
+
+adx:
+  # --- Baidu ADX ---
+  baidu-adx-endpoint: "http://adsp.baidu.com/jbssp"
+  baidu-conversion-base-url: "https://media-interact-test.baidu.com"
+  baidu-customer-name: dingzhaoming111
+  baidu-secret: gk780scz3oi2
+
+  # --- Redis ---
+  redis-addr: "cq-crs-47p6pmwo.sql.tencentcdb.com:28036"
+  redis-username: hcst
+  redis-password: "hcst@2026qwe.."
+  redis-db: 0
+
+  # --- TiDB/MySQL ---
+  tidb-url: "jdbc:mysql://139.186.172.149:3390/adx_proxy?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&connectTimeout=5000&socketTimeout=30000"
+  tidb-username: hcst
+  tidb-password: "hcst@2025"
+
+  # --- Task ---
+  skip-leader-election: false
+
+  # --- Conversion Sync ---
+  conversion-sync-enabled: true
+  conversion-sync-interval: 5s
+  conversion-sync-date-offset-days: 0
+  conversion-sync-page-size: 1
+
+  # --- Callback Retry ---
+  callback-retry-enabled: true
+  callback-retry-interval: 300s

+ 0 - 68
src/main/resources/application.properties

@@ -1,68 +0,0 @@
-# --- Server -------------------------------------------------------
-server.port=8787
-
-# --- Auto-configuration exclusions --------------------------------
-spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
-
-# --- Baidu ADX -----------------------------------------------------
-adx.baidu-adx-endpoint=http://adsp.baidu.com/jbssp
-adx.baidu-conversion-base-url=https://media-interact-test.baidu.com
-adx.baidu-customer-name=dingzhaoming111
-adx.baidu-secret=gk780scz3oi2
-adx.baidu-auction-price-encryption=aes-128-cbc
-adx.baidu-auction-price-e-key=192c728294891ef6
-adx.baidu-auction-price-i-key=ee64e8c430a2510e
-adx.baidu-media-id=1213
-adx.baidu-android-app-id=dcb4cbec
-adx.baidu-android-tag-ids=jlt52,jlt53,jlt54,jlt55,jlt56,jlt57,jlt58,jlt59,jlt60,jlt61,jlt62,jlt63,jlt64,jlt65,jlt66,jlt67,jlt68,jlt69,jlt70,jlt71,jlt72,jlt73,jlt74,jlt75,jlt76,jlt77,jlt78,jlt79,jlt80,jlt81,jlt82,jlt83,jlt84,jlt85,jlt86,jlt87,jlt88,jlt89,jlt90,jlt91,jlt92,jlt93,jlt94,jlt95,jlt96,jlt97,jlt98,jlt99,jlt100,jlt101
-adx.baidu-ios-app-id=efff0562
-adx.baidu-ios-tag-ids=jlt01,jlt03,jlt04,jlt05,jlt06,jlt07,jlt08,jlt09,jlt10,jlt11,jlt12,jlt13,jlt14,jlt15,jlt16,jlt17,jlt18,jlt19,jlt20,jlt21,jlt22,jlt23,jlt24,jlt25,jlt26,jlt27,jlt28,jlt29,jlt30,jlt31,jlt32,jlt33,jlt34,jlt35,jlt36,jlt37,jlt38,jlt39,jlt40,jlt41,jlt42,jlt43,jlt44,jlt45,jlt46,jlt47,jlt48,jlt49,jlt50,jlt51
-adx.baidu-bid-floor=0
-adx.baidu-action-type=1
-
-# --- Redis ---------------------------------------------------------
-adx.redis-addr=cq-crs-47p6pmwo.sql.tencentcdb.com:28036
-adx.redis-username=hcst
-adx.redis-password=hcst@2026qwe..
-adx.redis-db=0
-adx.redis-stream=adx:events
-adx.redis-stream-max-len=50000
-adx.bid-ttl=24h
-
-# --- TiDB/MySQL ----------------------------------------------------
-adx.tidb-url=jdbc:mysql://139.186.172.149:3390/adx_proxy?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&connectTimeout=5000&socketTimeout=30000
-adx.tidb-username=hcst
-adx.tidb-password=hcst@2025
-
-# --- Task Lock -----------------------------------------------------
-adx.task-lock-ttl=120s
-adx.task-lock-renew-interval=30s
-adx.task-lock-retry-interval=15s
- # -- true?????
-adx.skip-leader-election=true
-
-# --- Worker --------------------------------------------------------
-adx.worker-group=cold-writers
-adx.worker-consumer=server-1
-adx.worker-batch=100
-
-# --- Conversion Sync -----------------------------------------------
-adx.conversion-sync-enabled=true
-adx.conversion-sync-interval=5s
-adx.conversion-sync-date-offset-days=0
-adx.conversion-sync-page-size=1
-adx.conversion-sync-acts=1,2,3,4,5,6,8
-
-# --- Kuaishou Act Map -----------------------------------------------
-# Go env: KUAISHOU_ACT_MAP= (empty -> Java default new HashMap)
-# Go env: KUAISHOU_EXTRA_ACT_MAP=3:1
-# Go env: REDIS_STREAM_MAXLEN=50000 -> see adx.redis-stream-max-len above
-adx.kuaishou-extra-act-map.3=1
-
-# --- Callback Retry ------------------------------------------------
-adx.callback-retry-enabled=true
-adx.callback-retry-interval=300s
-adx.callback-retry-limit=100
-
-# --- Jackson -------------------------------------------------------
-spring.jackson.default-property-inclusion=non_null

+ 31 - 0
src/main/resources/application.yml

@@ -0,0 +1,31 @@
+# ============================================================
+# 公共配置(所有环境共享)
+# ============================================================
+
+spring:
+  profiles:
+    active: '@profileActive@'
+  autoconfigure:
+    exclude:
+      - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
+      - org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
+  jackson:
+    default-property-inclusion: non_null
+
+server:
+  port: 8787
+
+adx:
+  # --- Baidu ADX ---
+  baidu-auction-price-encryption: aes-128-cbc
+  baidu-auction-price-e-key: 192c728294891ef6
+  baidu-auction-price-i-key: ee64e8c430a2510e
+  baidu-media-id: 1213
+  baidu-android-app-id: dcb4cbec
+  baidu-android-tag-ids: jlt52,jlt53,jlt54,jlt55,jlt56,jlt57,jlt58,jlt59,jlt60,jlt61,jlt62,jlt63,jlt64,jlt65,jlt66,jlt67,jlt68,jlt69,jlt70,jlt71,jlt72,jlt73,jlt74,jlt75,jlt76,jlt77,jlt78,jlt79,jlt80,jlt81,jlt82,jlt83,jlt84,jlt85,jlt86,jlt87,jlt88,jlt89,jlt90,jlt91,jlt92,jlt93,jlt94,jlt95,jlt96,jlt97,jlt98,jlt99,jlt100,jlt101
+  baidu-ios-app-id: efff0562
+  baidu-ios-tag-ids: jlt01,jlt03,jlt04,jlt05,jlt06,jlt07,jlt08,jlt09,jlt10,jlt11,jlt12,jlt13,jlt14,jlt15,jlt16,jlt17,jlt18,jlt19,jlt20,jlt21,jlt22,jlt23,jlt24,jlt25,jlt26,jlt27,jlt28,jlt29,jlt30,jlt31,jlt32,jlt33,jlt34,jlt35,jlt36,jlt37,jlt38,jlt39,jlt40,jlt41,jlt42,jlt43,jlt44,jlt45,jlt46,jlt47,jlt48,jlt49,jlt50,jlt51
+
+  # --- Kuaishou Act Map ---
+  kuaishou-extra-act-map:
+    "3": 1