diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 813358e..6def26b 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -105,14 +105,6 @@ services: retries: 5 start_period: 60s restart: unless-stopped - deploy: - resources: - limits: - memory: 1G - cpus: "1.0" - reservations: - memory: 256M - cpus: "0.3" # TYAPI Worker 服务 tyapi-worker: @@ -147,14 +139,6 @@ services: retries: 5 start_period: 60s restart: unless-stopped - deploy: - resources: - limits: - memory: 512M - cpus: "0.5" - reservations: - memory: 128M - cpus: "0.1" # Asynq 任务监控 (生产环境) asynq-monitor: diff --git a/internal/domains/api/services/processors/pdfg/pdfg01gz_processor.go b/internal/domains/api/services/processors/pdfg/pdfg01gz_processor.go index a247aec..b287a8f 100644 --- a/internal/domains/api/services/processors/pdfg/pdfg01gz_processor.go +++ b/internal/domains/api/services/processors/pdfg/pdfg01gz_processor.go @@ -31,8 +31,8 @@ func ProcessPDFG01GZRequest(ctx context.Context, params []byte, deps *processors // 获取全局logger zapLogger := logger.GetGlobalLogger() - // Debug:记录入口参数 - zapLogger.Debug("PDFG01GZ请求开始", + // Debug:记录入口参数(使用 Info 级别便于线上查看) + logger.L().Info("PDFG01GZ请求开始", zap.String("name", paramsDto.Name), zap.String("id_card", paramsDto.IDCard), zap.String("mobile_no", paramsDto.MobileNo), @@ -56,8 +56,8 @@ func ProcessPDFG01GZRequest(ctx context.Context, params []byte, deps *processors if cfg, ok := ctx.Value("config").(*config.Config); ok && cfg != nil { maxSize = cfg.PDFGen.Cache.MaxSize - // Debug:记录PDF生成服务配置 - zapLogger.Debug("PDFG01GZ加载配置", + // Debug:记录PDF生成服务配置(使用 Info 级别便于线上查看) + logger.L().Info("PDFG01GZ加载配置", zap.String("env", cfg.App.Env), zap.String("pdfgen_production_url", cfg.PDFGen.ProductionURL), zap.String("pdfgen_development_url", cfg.PDFGen.DevelopmentURL), @@ -93,24 +93,29 @@ func ProcessPDFG01GZRequest(ctx context.Context, params []byte, deps *processors pdfGenService = pdfgen.NewPDFGenService(defaultCfg, zapLogger) } - // 检查缓存 + // 检查缓存(基于姓名+身份证) _, hit, createdAt, err := cacheManager.Get(paramsDto.Name, paramsDto.IDCard) if err != nil { zapLogger.Warn("检查缓存失败,继续生成PDF", zap.Error(err)) } else if hit { + // 计算缓存键,作为报告ID(可持久化) + reportID := cacheManager.GetCacheKey(paramsDto.Name, paramsDto.IDCard) + // 缓存命中,模拟慢几秒 zapLogger.Info("PDF缓存命中,返回缓存文件", zap.String("name", paramsDto.Name), zap.String("id_card", paramsDto.IDCard), + zap.String("report_id", reportID), zap.Time("created_at", createdAt), ) // 模拟慢几秒(2-4秒) time.Sleep(2 * time.Second) - // 生成下载链接 - downloadURL := generateDownloadURL(paramsDto.Name, paramsDto.IDCard) + // 生成下载链接(基于报告ID) + downloadURL := generateDownloadURL(reportID) return json.Marshal(map[string]interface{}{ "download_url": downloadURL, + "report_id": reportID, "cached": true, "created_at": createdAt.Format(time.RFC3339), }) @@ -130,7 +135,7 @@ func ProcessPDFG01GZRequest(ctx context.Context, params []byte, deps *processors // 打印完整的apiData(为避免日志过大,这里直接序列化为JSON字符串) apiDataBytes, _ := json.Marshal(apiData) - zapLogger.Debug("PDFG01GZ数据准备完成", + logger.L().Info("PDFG01GZ数据准备完成", zap.Int("api_data_count", len(apiData)), zap.Int("formatted_items", len(formattedData)), zap.ByteString("api_data", apiDataBytes), @@ -150,6 +155,9 @@ func ProcessPDFG01GZRequest(ctx context.Context, params []byte, deps *processors reportNumber = generateReportNumber() } + // 计算报告ID(与缓存键一致,便于通过ID直接下载) + reportID := cacheManager.GetCacheKey(paramsDto.Name, paramsDto.IDCard) + // 构建PDF生成请求 pdfReq := &pdfgen.GeneratePDFRequest{ Data: formattedData, @@ -159,11 +167,10 @@ func ProcessPDFG01GZRequest(ctx context.Context, params []byte, deps *processors // 调用PDF生成服务 // 即使部分子处理器失败,只要有APPLICANT_BASIC_INFO就可以生成PDF - zapLogger.Debug("PDFG01GZ开始调用PDF生成服务", + logger.L().Info("PDFG01GZ开始调用PDF生成服务", zap.String("report_number", reportNumber), zap.Int("data_items", len(formattedData)), ) - pdfResp, err := pdfGenService.GenerateGuangzhouPDF(ctx, pdfReq) if err != nil { zapLogger.Error("生成PDF失败", @@ -173,24 +180,26 @@ func ProcessPDFG01GZRequest(ctx context.Context, params []byte, deps *processors return nil, errors.Join(processors.ErrSystem, fmt.Errorf("生成PDF失败: %w", err)) } - // 保存到缓存 + // 保存到缓存(基于姓名+身份证) if err := cacheManager.Set(paramsDto.Name, paramsDto.IDCard, pdfResp.PDFBytes); err != nil { zapLogger.Warn("保存PDF到缓存失败", zap.Error(err)) // 不影响返回结果,只记录警告 } - // 生成下载链接 - downloadURL := generateDownloadURL(paramsDto.Name, paramsDto.IDCard) + // 生成下载链接(基于报告ID) + downloadURL := generateDownloadURL(reportID) zapLogger.Info("PDF生成成功", zap.String("name", paramsDto.Name), zap.String("id_card", paramsDto.IDCard), + zap.String("report_id", reportID), zap.String("report_number", reportNumber), zap.String("download_url", downloadURL), ) return json.Marshal(map[string]interface{}{ "download_url": downloadURL, + "report_id": reportID, "report_number": reportNumber, "cached": false, }) @@ -491,10 +500,10 @@ func generateReportNumber() string { return fmt.Sprintf("RPT%s", time.Now().Format("20060102150405")) } -// generateDownloadURL 生成下载链接 -func generateDownloadURL(name, idCard string) string { +// generateDownloadURL 生成下载链接(基于报告ID/缓存键) +func generateDownloadURL(reportID string) string { // 这里应该生成实际的下载URL // 暂时返回一个占位符,实际应该根据服务器配置生成 - return fmt.Sprintf("/api/v1/pdfg/download?name=%s&id_card=%s", name, idCard) + return fmt.Sprintf("/api/v1/pdfg/download?id=%s", reportID) } diff --git a/internal/infrastructure/external/pdfgen/pdfgen_service.go b/internal/infrastructure/external/pdfgen/pdfgen_service.go index ba21aac..a5b1c0a 100644 --- a/internal/infrastructure/external/pdfgen/pdfgen_service.go +++ b/internal/infrastructure/external/pdfgen/pdfgen_service.go @@ -93,12 +93,6 @@ func (s *PDFGenService) GenerateGuangzhouPDF(ctx context.Context, req *GenerateP return nil, fmt.Errorf("序列化请求失败: %w", err) } - // Debug:打印请求体预览(最多1024字节),防止日志过大 - bodyPreview := reqBody - if len(bodyPreview) > 1024 { - bodyPreview = bodyPreview[:1024] - } - // 构建请求URL url := fmt.Sprintf("%s%s", s.baseURL, s.apiPath) @@ -117,7 +111,7 @@ func (s *PDFGenService) GenerateGuangzhouPDF(ctx context.Context, req *GenerateP s.logger.Info("开始调用PDF生成服务", zap.String("url", url), zap.Int("data_count", len(req.Data)), - zap.ByteString("body_preview", bodyPreview), + zap.ByteString("reqBody", reqBody), ) resp, err := s.client.Do(httpReq) diff --git a/internal/infrastructure/http/handlers/pdfg_handler.go b/internal/infrastructure/http/handlers/pdfg_handler.go index fb4740d..2f3f1b1 100644 --- a/internal/infrastructure/http/handlers/pdfg_handler.go +++ b/internal/infrastructure/http/handlers/pdfg_handler.go @@ -33,22 +33,20 @@ func NewPDFGHandler( } // DownloadPDF 下载PDF文件 -// GET /api/v1/pdfg/download?name=xxx&id_card=xxx +// GET /api/v1/pdfg/download?id=报告ID func (h *PDFGHandler) DownloadPDF(c *gin.Context) { - name := c.Query("name") - idCard := c.Query("id_card") + reportID := c.Query("id") - if name == "" || idCard == "" { - h.responseBuilder.BadRequest(c, "姓名和身份证号不能为空") + if reportID == "" { + h.responseBuilder.BadRequest(c, "报告ID不能为空") return } // 从缓存获取PDF - pdfBytes, hit, createdAt, err := h.cacheManager.Get(name, idCard) + pdfBytes, hit, createdAt, err := h.cacheManager.GetByCacheKey(reportID) if err != nil { h.logger.Error("获取PDF缓存失败", - zap.String("name", name), - zap.String("id_card", idCard), + zap.String("report_id", reportID), zap.Error(err), ) h.responseBuilder.InternalError(c, "获取PDF文件失败") @@ -57,8 +55,7 @@ func (h *PDFGHandler) DownloadPDF(c *gin.Context) { if !hit { h.logger.Warn("PDF文件不存在或已过期", - zap.String("name", name), - zap.String("id_card", idCard), + zap.String("report_id", reportID), ) h.responseBuilder.NotFound(c, "PDF文件不存在或已过期,请重新生成") return @@ -68,8 +65,7 @@ func (h *PDFGHandler) DownloadPDF(c *gin.Context) { expiresAt := createdAt.Add(24 * time.Hour) if time.Now().After(expiresAt) { h.logger.Warn("PDF文件已过期", - zap.String("name", name), - zap.String("id_card", idCard), + zap.String("report_id", reportID), zap.Time("expires_at", expiresAt), ) h.responseBuilder.NotFound(c, "PDF文件已过期,请重新生成") @@ -85,8 +81,7 @@ func (h *PDFGHandler) DownloadPDF(c *gin.Context) { c.Data(http.StatusOK, "application/pdf", pdfBytes) h.logger.Info("PDF文件下载成功", - zap.String("name", name), - zap.String("id_card", idCard), + zap.String("report_id", reportID), zap.Int("file_size", len(pdfBytes)), ) } diff --git a/internal/shared/pdf/pdf_cache_manager.go b/internal/shared/pdf/pdf_cache_manager.go index 4874838..c4b0aa7 100644 --- a/internal/shared/pdf/pdf_cache_manager.go +++ b/internal/shared/pdf/pdf_cache_manager.go @@ -98,6 +98,13 @@ func (m *PDFCacheManager) GetByProduct(productID, version string) ([]byte, bool, return pdfBytes, hit, err } +// GetByCacheKey 通过缓存键直接获取PDF文件 +// 适用于已经持久化了缓存键(例如作为报告ID)的场景 +// 返回PDF字节流、是否命中缓存、文件创建时间、错误 +func (m *PDFCacheManager) GetByCacheKey(cacheKey string) ([]byte, bool, time.Time, error) { + return m.getByKey(cacheKey, "", "") +} + // getByKey 内部方法:根据缓存键获取文件 func (m *PDFCacheManager) getByKey(cacheKey string, key1, key2 string) ([]byte, bool, time.Time, error) { cachePath := m.GetCachePath(cacheKey)