111
This commit is contained in:
parent
777611e996
commit
15ea020bc1
|
|
@ -1 +1 @@
|
||||||
[{"name":"gid","value":"yjfKDJiJ0J7SyjfKDJi8Dqf884ufUMYf3MlIVqfYTYl3D3q8Svu0VW888yyYW4Y8JD0j8Yd2","domain":".xiaohongshu.com","path":"/","expires":1810179744.008933,"size":75,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"a1","value":"19d6b2f0b04zdps8dison8k8oibcyzaju3ji7d03d30000118748","domain":".xiaohongshu.com","path":"/","expires":1807155738,"size":54,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"galaxy.creator.beaker.session.id","value":"1775619757404082990054","domain":".xiaohongshu.com","path":"/","expires":1778211755.091605,"size":54,"httpOnly":true,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"sec_poison_id","value":"ec8ce30d-a35e-484c-8f64-392a85f99705","domain":".xiaohongshu.com","path":"/","expires":1775762101,"size":49,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"x-user-id-creator.xiaohongshu.com","value":"65d74a4c0000000005032a98","domain":".xiaohongshu.com","path":"/","expires":1810179755.091531,"size":57,"httpOnly":true,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"customerClientId","value":"231145420384063","domain":".xiaohongshu.com","path":"/","expires":1810179755.091552,"size":31,"httpOnly":true,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"loadts","value":"1775761630503","domain":".xiaohongshu.com","path":"/","expires":1807297630,"size":19,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"access-token-creator.xiaohongshu.com","value":"customer.creator.AT-68c517626228786611519495vggizcwmifuvnaaw","domain":".xiaohongshu.com","path":"/","expires":1778211754.091569,"size":96,"httpOnly":true,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"customer-sso-sid","value":"68c5176262287866115194944uxxdffhcemiwvwt","domain":".xiaohongshu.com","path":"/","expires":1776224554.091467,"size":56,"httpOnly":true,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"galaxy_creator_session_id","value":"nWC5PzTFCCSJsLYiRFLFORIWUoUf5c4Egr3v","domain":".xiaohongshu.com","path":"/","expires":1778211755.091586,"size":61,"httpOnly":true,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"webId","value":"f840cc8b10e0a01b0bdb839482af19d1","domain":".xiaohongshu.com","path":"/","expires":1807155738,"size":37,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"ets","value":"1775619738206","domain":".xiaohongshu.com","path":"/","expires":1778211738.206388,"size":16,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"xsecappid","value":"ugc","domain":".xiaohongshu.com","path":"/","expires":1807297630,"size":12,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"acw_tc","value":"0a00074d17757617587134822e6e92a5ae9bdad71669770468266647ffdc11","domain":"creator.xiaohongshu.com","path":"/","expires":1775763295.185423,"size":68,"httpOnly":true,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"websectiga","value":"29098a4cf41f76ee3f8db19051aaa60c0fc7c5e305572fec762da32d457d76ae","domain":".xiaohongshu.com","path":"/","expires":1776020696,"size":74,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443}]
|
[{"name":"websectiga","value":"7750c37de43b7be9de8ed9ff8ea0e576519e8cd2157322eb972ecb429a7735d4","domain":".xiaohongshu.com","path":"/","expires":1776073705,"size":74,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"x-user-id-creator.xiaohongshu.com","value":"65d74a4c0000000005032a98","domain":".xiaohongshu.com","path":"/","expires":1810179755.091531,"size":57,"httpOnly":true,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"xsecappid","value":"ugc","domain":".xiaohongshu.com","path":"/","expires":1807350714,"size":12,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"a1","value":"19d6b2f0b04zdps8dison8k8oibcyzaju3ji7d03d30000118748","domain":".xiaohongshu.com","path":"/","expires":1807155738,"size":54,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"webId","value":"f840cc8b10e0a01b0bdb839482af19d1","domain":".xiaohongshu.com","path":"/","expires":1807155738,"size":37,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"access-token-creator.xiaohongshu.com","value":"customer.creator.AT-68c517626228786611519495vggizcwmifuvnaaw","domain":".xiaohongshu.com","path":"/","expires":1778211754.091569,"size":96,"httpOnly":true,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"sec_poison_id","value":"0e8199c2-5b2c-4b5d-9423-9ce4ae7c7d4a","domain":".xiaohongshu.com","path":"/","expires":1775815110,"size":49,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"customerClientId","value":"231145420384063","domain":".xiaohongshu.com","path":"/","expires":1810179755.091552,"size":31,"httpOnly":true,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"ets","value":"1775619738206","domain":".xiaohongshu.com","path":"/","expires":1778211738.206388,"size":16,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"gid","value":"yjfKDJiJ0J7SyjfKDJi8Dqf884ufUMYf3MlIVqfYTYl3D3q8Svu0VW888yyYW4Y8JD0j8Yd2","domain":".xiaohongshu.com","path":"/","expires":1810372429.581067,"size":75,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"customer-sso-sid","value":"68c5176262287866115194944uxxdffhcemiwvwt","domain":".xiaohongshu.com","path":"/","expires":1776224554.091467,"size":56,"httpOnly":true,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"galaxy_creator_session_id","value":"nWC5PzTFCCSJsLYiRFLFORIWUoUf5c4Egr3v","domain":".xiaohongshu.com","path":"/","expires":1778211755.091586,"size":61,"httpOnly":true,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"acw_tc","value":"0a0d0eb817758145058628343eac7363daa6c0cadc9daf2e0f80b0fb928719","domain":"creator.xiaohongshu.com","path":"/","expires":1775816304.657778,"size":68,"httpOnly":true,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"galaxy.creator.beaker.session.id","value":"1775619757404082990054","domain":".xiaohongshu.com","path":"/","expires":1778211755.091605,"size":54,"httpOnly":true,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"loadts","value":"1775814714949","domain":".xiaohongshu.com","path":"/","expires":1807350714,"size":19,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443}]
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package manager
|
package manager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"geo/internal/config"
|
"geo/internal/config"
|
||||||
"geo/internal/entitys"
|
"geo/internal/entitys"
|
||||||
|
|
@ -14,6 +15,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -24,8 +27,8 @@ const (
|
||||||
StatusSuccess = 4
|
StatusSuccess = 4
|
||||||
|
|
||||||
// 默认并发worker数量
|
// 默认并发worker数量
|
||||||
DefaultWorkerNum = 2
|
DefaultWorkerNum = 4
|
||||||
MaxWorkerNum = 5
|
MaxWorkerNum = 100
|
||||||
)
|
)
|
||||||
|
|
||||||
// PublishManager 发布管理器
|
// PublishManager 发布管理器
|
||||||
|
|
@ -186,40 +189,62 @@ func (pm *PublishManager) executeOneTask(workerID int, headless bool) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if task == nil {
|
if task == nil {
|
||||||
time.Sleep(10 * time.Second)
|
time.Sleep(30 * time.Second)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("[Worker-%d] 开始处理任务 requestID=%s", workerID, task.RequestID)
|
log.Printf("[Worker-%d] 开始处理任务 requestID=%s", workerID, task.RequestID)
|
||||||
result := pm.processTask(task, headless)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
|
||||||
if result == nil {
|
defer cancel()
|
||||||
log.Printf("[Worker-%d] 任务失败: %s", workerID, result.Message)
|
// 使用 channel 接收结果,避免 goroutine 泄漏
|
||||||
} else {
|
|
||||||
if result.Success {
|
|
||||||
log.Printf("[Worker-%d] 任务成功: %s", workerID, result.Message)
|
|
||||||
} else {
|
|
||||||
log.Printf("[Worker-%d] 任务失败: %s", workerID, result.Message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
result := pm.processTask(ctx, task, headless)
|
||||||
|
|
||||||
|
if result == nil {
|
||||||
|
log.Printf("[Worker-%d] 任务返回空结果", workerID)
|
||||||
|
} else if result.Success {
|
||||||
|
log.Printf("[Worker-%d] 任务成功: %s", workerID, result.Message)
|
||||||
|
} else {
|
||||||
|
log.Printf("[Worker-%d] 任务失败: %s", workerID, result.Message)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// acquireTask 原子获取一个待发布任务(使用 GORM 事务 + FOR UPDATE SKIP LOCKED)
|
// acquireTask 原子获取一个待发布任务(使用 GORM 事务 + FOR UPDATE SKIP LOCKED)
|
||||||
func (pm *PublishManager) acquireTask() (*entitys.PublishTaskDetail, error) {
|
func (pm *PublishManager) acquireTask() (*entitys.PublishTaskDetail, error) {
|
||||||
currentTime := time.Now().Format("2006-01-02 15:04:05")
|
currentTime := time.Now().Format("2006-01-02 15:04:05")
|
||||||
|
uid := uuid.NewString()[:16]
|
||||||
|
// 使用子查询先找出要更新的 request_id
|
||||||
|
updateSQL := `
|
||||||
|
UPDATE publish p
|
||||||
|
SET p.status = ?,uid=?
|
||||||
|
WHERE p.request_id = (
|
||||||
|
SELECT request_id FROM (
|
||||||
|
SELECT p2.request_id
|
||||||
|
FROM publish p2
|
||||||
|
INNER JOIN plat pl ON p2.plat_index COLLATE utf8mb4_unicode_ci = pl.index
|
||||||
|
WHERE p2.token_id = ?
|
||||||
|
AND p2.status = ?
|
||||||
|
AND p2.publish_time <= ?
|
||||||
|
AND pl.status = 1
|
||||||
|
ORDER BY p2.publish_time ASC
|
||||||
|
LIMIT 1
|
||||||
|
) AS tmp
|
||||||
|
)
|
||||||
|
AND p.status = ?
|
||||||
|
`
|
||||||
|
|
||||||
// 开启事务
|
result := pm.db.Client.Exec(updateSQL, StatusProcessing, uid, pm.TokenID, StatusPending, currentTime, StatusPending)
|
||||||
tx := pm.db.Client.Begin()
|
if result.Error != nil {
|
||||||
if tx.Error != nil {
|
return nil, result.Error
|
||||||
return nil, fmt.Errorf("开启事务失败: %v", tx.Error)
|
|
||||||
}
|
}
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
tx.Rollback()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
selectSQL := `
|
if result.RowsAffected == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询刚更新的任务
|
||||||
|
var task entitys.PublishTaskDetail
|
||||||
|
querySQL := `
|
||||||
SELECT
|
SELECT
|
||||||
p.request_id,
|
p.request_id,
|
||||||
p.plat_index,
|
p.plat_index,
|
||||||
|
|
@ -238,46 +263,32 @@ func (pm *PublishManager) acquireTask() (*entitys.PublishTaskDetail, error) {
|
||||||
pl.desc
|
pl.desc
|
||||||
FROM publish p
|
FROM publish p
|
||||||
INNER JOIN plat pl ON p.plat_index COLLATE utf8mb4_unicode_ci = pl.index AND pl.status = 1
|
INNER JOIN plat pl ON p.plat_index COLLATE utf8mb4_unicode_ci = pl.index AND pl.status = 1
|
||||||
WHERE p.token_id = ? AND p.status = ? AND p.publish_time <= ?
|
WHERE uid=? AND p.token_id = ?
|
||||||
ORDER BY p.publish_time ASC
|
ORDER BY p.publish_time DESC
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
FOR UPDATE SKIP LOCKED
|
|
||||||
`
|
`
|
||||||
var task entitys.PublishTaskDetail
|
|
||||||
err := tx.Raw(selectSQL, pm.TokenID, StatusPending, currentTime).Scan(&task).Error
|
err := pm.db.Client.Raw(querySQL, uid, pm.TokenID).Scan(&task).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tx.Rollback()
|
return nil, err
|
||||||
return nil, fmt.Errorf("查询任务失败: %v", err)
|
|
||||||
}
|
|
||||||
if task.RequestID == "" {
|
|
||||||
tx.Rollback()
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
updateSQL := "UPDATE publish SET status = ? WHERE request_id = ? AND status = ?"
|
|
||||||
result := tx.Exec(updateSQL, StatusProcessing, task.RequestID, StatusPending)
|
|
||||||
if result.Error != nil {
|
|
||||||
tx.Rollback()
|
|
||||||
return nil, fmt.Errorf("更新任务状态失败: %v", result.Error)
|
|
||||||
}
|
|
||||||
if result.RowsAffected == 0 {
|
|
||||||
tx.Rollback()
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := tx.Commit().Error; err != nil {
|
|
||||||
return nil, fmt.Errorf("提交事务失败: %v", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &task, nil
|
return &task, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// processTask 处理单个任务
|
// processTask 处理单个任务
|
||||||
func (pm *PublishManager) processTask(publishData *entitys.PublishTaskDetail, headless bool) *SingleResult {
|
func (pm *PublishManager) processTask(ctx context.Context, publishData *entitys.PublishTaskDetail, headless bool) *SingleResult {
|
||||||
if publishData == nil || publishData.RequestID == "" {
|
if publishData == nil || publishData.RequestID == "" {
|
||||||
return &SingleResult{Success: false, Message: "无效的任务数据"}
|
return &SingleResult{Success: false, Message: "无效的任务数据"}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查 context 是否已取消
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return &SingleResult{Success: false, Message: "任务被取消: " + ctx.Err().Error(), RequestId: publishData.RequestID}
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
taskLogger, logFile, err := pm.getTaskLogger(publishData.RequestID)
|
taskLogger, logFile, err := pm.getTaskLogger(publishData.RequestID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[任务 %s] 创建日志文件失败: %v,使用全局日志", publishData.RequestID, err)
|
log.Printf("[任务 %s] 创建日志文件失败: %v,使用全局日志", publishData.RequestID, err)
|
||||||
|
|
@ -331,7 +342,7 @@ func (pm *PublishManager) processTask(publishData *entitys.PublishTaskDetail, he
|
||||||
params.ImagePath = imgPath
|
params.ImagePath = imgPath
|
||||||
params.SourcePath = docPath
|
params.SourcePath = docPath
|
||||||
|
|
||||||
pub := publisherClass.InitMethod(params, pm.Conf, taskLogger)
|
pub := publisherClass.InitMethod(ctx, params, pm.Conf, taskLogger)
|
||||||
taskLogger.Printf("[任务 %s] 开始执行发布...", publishData.RequestID)
|
taskLogger.Printf("[任务 %s] 开始执行发布...", publishData.RequestID)
|
||||||
success, message := pub.PublishNote()
|
success, message := pub.PublishNote()
|
||||||
|
|
||||||
|
|
@ -349,7 +360,7 @@ func (pm *PublishManager) processTask(publishData *entitys.PublishTaskDetail, he
|
||||||
}
|
}
|
||||||
|
|
||||||
// RetryTask 重试任务(非无头模式)
|
// RetryTask 重试任务(非无头模式)
|
||||||
func (pm *PublishManager) RetryTask(requestID string) *SingleResult {
|
func (pm *PublishManager) RetryTask(ctx context.Context, requestID string) *SingleResult {
|
||||||
if requestID == "" {
|
if requestID == "" {
|
||||||
return &SingleResult{Success: false, Message: "requestID不能为空"}
|
return &SingleResult{Success: false, Message: "requestID不能为空"}
|
||||||
}
|
}
|
||||||
|
|
@ -360,7 +371,7 @@ func (pm *PublishManager) RetryTask(requestID string) *SingleResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("[重试] 开始重试任务 requestID=%s(非无头模式)", requestID)
|
log.Printf("[重试] 开始重试任务 requestID=%s(非无头模式)", requestID)
|
||||||
result := pm.processTask(publishData, false)
|
result := pm.processTask(ctx, publishData, false)
|
||||||
if result == nil {
|
if result == nil {
|
||||||
result = &SingleResult{Success: false, Message: "系统故障", RequestId: requestID}
|
result = &SingleResult{Success: false, Message: "系统故障", RequestId: requestID}
|
||||||
}
|
}
|
||||||
|
|
@ -498,9 +509,9 @@ func (pm *PublishManager) updatePublishStatus(requestID string, status int, mess
|
||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
if message != "" {
|
if message != "" {
|
||||||
_, err = pm.db.Execute("UPDATE publish SET status = ?, msg = ? WHERE request_id = ?", status, message, requestID)
|
_, err = pm.db.Execute("UPDATE publish SET status = ?, msg = ? WHERE token_id=? AND request_id = ?", status, message, pm.TokenID, requestID)
|
||||||
} else {
|
} else {
|
||||||
_, err = pm.db.Execute("UPDATE publish SET status = ? WHERE request_id = ?", status, requestID)
|
_, err = pm.db.Execute("UPDATE publish SET status = ? WHERE token_id=? AND request_id = ?", status, pm.TokenID, requestID)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("更新发布状态失败: requestID=%s, status=%d, error=%v", requestID, status, err)
|
log.Printf("更新发布状态失败: requestID=%s, status=%d, error=%v", requestID, status, err)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package publisher
|
package publisher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"geo/internal/config"
|
"geo/internal/config"
|
||||||
"log"
|
"log"
|
||||||
|
|
@ -15,8 +16,8 @@ type BaijiahaoPublisher struct {
|
||||||
*BasePublisher
|
*BasePublisher
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBaijiahaoPublisher(task *TaskParams, cfg *config.Config, logger *log.Logger) PublisherInerface {
|
func NewBaijiahaoPublisher(ctx context.Context, task *TaskParams, cfg *config.Config, logger *log.Logger) PublisherInerface {
|
||||||
return &BaijiahaoPublisher{NewBasePublisher(task, cfg, logger)}
|
return &BaijiahaoPublisher{NewBasePublisher(ctx, task, cfg, logger)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BaijiahaoPublisher) CheckLoginStatus() bool {
|
func (p *BaijiahaoPublisher) CheckLoginStatus() bool {
|
||||||
|
|
@ -92,18 +93,12 @@ func (p *BaijiahaoPublisher) checkElementExists(selector string, timeout int) bo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BaijiahaoPublisher) PublishNote() (bool, string) {
|
func (p *BaijiahaoPublisher) PublishNote() (bool, string) {
|
||||||
driverCreated := false
|
|
||||||
defer func() {
|
|
||||||
if driverCreated && p.Browser != nil {
|
|
||||||
p.Close()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err := p.SetupDriver(); err != nil {
|
if err := p.SetupDriver(); err != nil {
|
||||||
return false, fmt.Sprintf("浏览器启动失败: %v", err)
|
return false, fmt.Sprintf("浏览器启动失败: %v", err)
|
||||||
}
|
}
|
||||||
driverCreated = true
|
|
||||||
|
|
||||||
|
defer p.Page.Close()
|
||||||
if p.LoadCookies() == nil {
|
if p.LoadCookies() == nil {
|
||||||
p.Page.MustNavigate(p.EditorURL)
|
p.Page.MustNavigate(p.EditorURL)
|
||||||
p.WaitForPageReady(5)
|
p.WaitForPageReady(5)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package publisher
|
package publisher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"geo/internal/entitys"
|
"geo/internal/entitys"
|
||||||
|
|
@ -11,12 +12,14 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"geo/internal/config"
|
"geo/internal/config"
|
||||||
|
|
||||||
"github.com/go-rod/rod"
|
"github.com/go-rod/rod"
|
||||||
"github.com/go-rod/rod/lib/launcher"
|
"github.com/go-rod/rod/lib/launcher"
|
||||||
"github.com/go-rod/rod/lib/proto"
|
"github.com/go-rod/rod/lib/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BasePublisher struct {
|
type BasePublisher struct {
|
||||||
|
ctx context.Context
|
||||||
Headless bool
|
Headless bool
|
||||||
Title string
|
Title string
|
||||||
Content string
|
Content string
|
||||||
|
|
@ -61,7 +64,7 @@ type TaskParams struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBasePublisher 构造函数,增加 logger 参数
|
// NewBasePublisher 构造函数,增加 logger 参数
|
||||||
func NewBasePublisher(task *TaskParams, config *config.Config, logger *log.Logger) *BasePublisher {
|
func NewBasePublisher(ctx context.Context, task *TaskParams, config *config.Config, logger *log.Logger) *BasePublisher {
|
||||||
cookiesDir := filepath.Join(config.Sys.CookiesDir, task.UserIndex)
|
cookiesDir := filepath.Join(config.Sys.CookiesDir, task.UserIndex)
|
||||||
os.MkdirAll(cookiesDir, 0755)
|
os.MkdirAll(cookiesDir, 0755)
|
||||||
cookiesFile := filepath.Join(cookiesDir, task.PlatIndex+".json")
|
cookiesFile := filepath.Join(cookiesDir, task.PlatIndex+".json")
|
||||||
|
|
@ -85,6 +88,7 @@ func NewBasePublisher(task *TaskParams, config *config.Config, logger *log.Logge
|
||||||
}
|
}
|
||||||
|
|
||||||
return &BasePublisher{
|
return &BasePublisher{
|
||||||
|
ctx: ctx,
|
||||||
Headless: task.Headless,
|
Headless: task.Headless,
|
||||||
Title: task.Title,
|
Title: task.Title,
|
||||||
Content: task.Content,
|
Content: task.Content,
|
||||||
|
|
@ -109,9 +113,10 @@ func NewBasePublisher(task *TaskParams, config *config.Config, logger *log.Logge
|
||||||
|
|
||||||
func (b *BasePublisher) SetupDriver() error {
|
func (b *BasePublisher) SetupDriver() error {
|
||||||
b.LogInfo("初始化浏览器。。。。")
|
b.LogInfo("初始化浏览器。。。。")
|
||||||
b.Headless = false
|
b.Headless = true
|
||||||
l := launcher.New().Bin(b.config.Sys.ChromePath)
|
l := launcher.New().Bin(b.config.Sys.ChromePath)
|
||||||
l.Headless(b.Headless)
|
l.Headless(b.Headless)
|
||||||
|
|
||||||
// 设置 Leakless 模式(解决 Windows 上的问题)
|
// 设置 Leakless 模式(解决 Windows 上的问题)
|
||||||
l.Leakless(false)
|
l.Leakless(false)
|
||||||
if b.Headless {
|
if b.Headless {
|
||||||
|
|
@ -122,7 +127,7 @@ func (b *BasePublisher) SetupDriver() error {
|
||||||
l.Set("disable-dev-shm-usage")
|
l.Set("disable-dev-shm-usage")
|
||||||
l.Set("no-sandbox")
|
l.Set("no-sandbox")
|
||||||
// 禁用虚拟滚动,避免等待
|
// 禁用虚拟滚动,避免等待
|
||||||
l.Set("disable-scroll-to-text-fragment")
|
//l.Set("disable-scroll-to-text-fragment")
|
||||||
}
|
}
|
||||||
// 设置用户数据目录
|
// 设置用户数据目录
|
||||||
|
|
||||||
|
|
@ -130,7 +135,12 @@ func (b *BasePublisher) SetupDriver() error {
|
||||||
os.MkdirAll(userDataDir, 0755)
|
os.MkdirAll(userDataDir, 0755)
|
||||||
|
|
||||||
l.UserDataDir(userDataDir)
|
l.UserDataDir(userDataDir)
|
||||||
|
// 为每个用户分配一个可用的随机端口,确保端口不冲突
|
||||||
|
//freePort, err := pkg.GetFreePort()
|
||||||
|
//if err != nil {
|
||||||
|
// return fmt.Errorf("获取空闲端口失败: %v", err)
|
||||||
|
//}
|
||||||
|
l.Set("remote-debugging-port", "0")
|
||||||
// 关键优化:不重新使用已有的数据目录时不要清除
|
// 关键优化:不重新使用已有的数据目录时不要清除
|
||||||
l.Set("profile-directory", "Default")
|
l.Set("profile-directory", "Default")
|
||||||
|
|
||||||
|
|
@ -141,7 +151,6 @@ func (b *BasePublisher) SetupDriver() error {
|
||||||
l.Set("disable-gpu")
|
l.Set("disable-gpu")
|
||||||
l.Set("disable-software-rasterizer")
|
l.Set("disable-software-rasterizer")
|
||||||
l.Set("disable-setuid-sandbox")
|
l.Set("disable-setuid-sandbox")
|
||||||
l.Set("remote-debugging-port", "9222")
|
|
||||||
|
|
||||||
// 关键:禁用后台限制,让页面在后台也能正常执行
|
// 关键:禁用后台限制,让页面在后台也能正常执行
|
||||||
l.Set("disable-background-timer-throttling")
|
l.Set("disable-background-timer-throttling")
|
||||||
|
|
@ -159,12 +168,21 @@ func (b *BasePublisher) SetupDriver() error {
|
||||||
return fmt.Errorf("启动浏览器失败: %v", err)
|
return fmt.Errorf("启动浏览器失败: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
b.Browser = rod.New().ControlURL(url).MustConnect()
|
b.Browser = rod.New().Context(b.ctx).ControlURL(url).MustConnect()
|
||||||
b.Page = b.Browser.MustPage()
|
b.Page = b.Browser.MustPage()
|
||||||
|
time.Sleep(5000)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// func (b *BasePublisher) SetupDriver() error {
|
||||||
|
// b.LogInfo("初始化浏览器。。。。")
|
||||||
|
// b.Headless = true
|
||||||
|
//
|
||||||
|
// b.Browser = rod.New().Context(b.ctx).
|
||||||
|
// b.Page = b.Browser.MustPage()
|
||||||
|
// time.Sleep(5000)
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
func (b *BasePublisher) Close() {
|
func (b *BasePublisher) Close() {
|
||||||
if b.Page != nil {
|
if b.Page != nil {
|
||||||
b.Page.Close()
|
b.Page.Close()
|
||||||
|
|
@ -211,11 +229,11 @@ func (b *BasePublisher) RefreshPage() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BasePublisher) WaitForPageReady(timeout int) error {
|
func (b *BasePublisher) WaitForPageReady(timeout int) error {
|
||||||
return b.Page.Timeout(time.Duration(timeout) * time.Second).WaitLoad()
|
return b.Page.Context(b.ctx).WaitLoad()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BasePublisher) WaitForElement(selector string, timeout int) (*rod.Element, error) {
|
func (b *BasePublisher) WaitForElement(selector string, timeout int) (*rod.Element, error) {
|
||||||
return b.Page.Timeout(time.Duration(timeout) * time.Second).Element(selector)
|
return b.Page.Context(b.ctx).Element(selector)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BasePublisher) WaitForElementVisible(selector string, timeout int) (*rod.Element, error) {
|
func (b *BasePublisher) WaitForElementVisible(selector string, timeout int) (*rod.Element, error) {
|
||||||
|
|
@ -246,7 +264,6 @@ func (b *BasePublisher) JSClick(element *rod.Element) error {
|
||||||
return fmt.Errorf("element is nil")
|
return fmt.Errorf("element is nil")
|
||||||
}
|
}
|
||||||
err := element.Click(proto.InputMouseButtonLeft, 1)
|
err := element.Click(proto.InputMouseButtonLeft, 1)
|
||||||
// 方法1:使用 rod 自带的 Click
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Logger.Printf("click fail:" + err.Error())
|
b.Logger.Printf("click fail:" + err.Error())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package publisher
|
package publisher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"geo/internal/config"
|
"geo/internal/config"
|
||||||
"log"
|
"log"
|
||||||
|
|
@ -14,8 +15,8 @@ type CSDNPublisher struct {
|
||||||
*BasePublisher
|
*BasePublisher
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCSDNPublisher(task *TaskParams, cfg *config.Config, logger *log.Logger) PublisherInerface {
|
func NewCSDNPublisher(ctx context.Context, task *TaskParams, cfg *config.Config, logger *log.Logger) PublisherInerface {
|
||||||
return &CSDNPublisher{NewBasePublisher(task, cfg, logger)}
|
return &CSDNPublisher{NewBasePublisher(ctx, task, cfg, logger)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *CSDNPublisher) CheckLogin() (bool, string) {
|
func (p *CSDNPublisher) CheckLogin() (bool, string) {
|
||||||
|
|
@ -185,7 +186,7 @@ func (p *CSDNPublisher) PublishNote() (bool, string) {
|
||||||
if err := p.SetupDriver(); err != nil {
|
if err := p.SetupDriver(); err != nil {
|
||||||
return false, fmt.Sprintf("浏览器启动失败: %v", err)
|
return false, fmt.Sprintf("浏览器启动失败: %v", err)
|
||||||
}
|
}
|
||||||
defer p.Close()
|
defer p.Page.Close()
|
||||||
|
|
||||||
// 执行发布流程
|
// 执行发布流程
|
||||||
steps := []struct {
|
steps := []struct {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package publisher
|
package publisher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"geo/internal/config"
|
"geo/internal/config"
|
||||||
"log"
|
"log"
|
||||||
|
|
@ -16,8 +17,8 @@ type DouyinSpPublisher struct {
|
||||||
*BasePublisher
|
*BasePublisher
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDouyinSpPublisher(task *TaskParams, cfg *config.Config, logger *log.Logger) PublisherInerface {
|
func NewDouyinSpPublisher(ctx context.Context, task *TaskParams, cfg *config.Config, logger *log.Logger) PublisherInerface {
|
||||||
return &DouyinSpPublisher{NewBasePublisher(task, cfg, logger)}
|
return &DouyinSpPublisher{NewBasePublisher(ctx, task, cfg, logger)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *DouyinSpPublisher) CheckLogin() (bool, string) {
|
func (p *DouyinSpPublisher) CheckLogin() (bool, string) {
|
||||||
|
|
@ -392,7 +393,7 @@ func (p *DouyinSpPublisher) PublishNote() (bool, string) {
|
||||||
if err := p.SetupDriver(); err != nil {
|
if err := p.SetupDriver(); err != nil {
|
||||||
return false, fmt.Sprintf("浏览器启动失败: %v", err)
|
return false, fmt.Sprintf("浏览器启动失败: %v", err)
|
||||||
}
|
}
|
||||||
defer p.Close()
|
defer p.Page.Close()
|
||||||
|
|
||||||
steps := []struct {
|
steps := []struct {
|
||||||
name string
|
name string
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package publisher
|
package publisher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"geo/internal/config"
|
"geo/internal/config"
|
||||||
"log"
|
"log"
|
||||||
)
|
)
|
||||||
|
|
@ -11,6 +12,7 @@ type PublisherInerface interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type NewPublisher func(
|
type NewPublisher func(
|
||||||
|
ctx context.Context,
|
||||||
param *TaskParams,
|
param *TaskParams,
|
||||||
cfg *config.Config,
|
cfg *config.Config,
|
||||||
logger *log.Logger) PublisherInerface
|
logger *log.Logger) PublisherInerface
|
||||||
|
|
@ -110,7 +112,7 @@ var PublisherMap = map[string]*PublisherValue{
|
||||||
InitMethod: NewCSDNPublisher,
|
InitMethod: NewCSDNPublisher,
|
||||||
ContentFormat: "markdown",
|
ContentFormat: "markdown",
|
||||||
ImgNeed: 1,
|
ImgNeed: 1,
|
||||||
Type: 2,
|
Type: 1,
|
||||||
WordContainImg: false,
|
WordContainImg: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package publisher
|
package publisher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"geo/internal/config"
|
"geo/internal/config"
|
||||||
"log"
|
"log"
|
||||||
|
|
@ -15,8 +16,8 @@ type JianshuPublisher struct {
|
||||||
*BasePublisher
|
*BasePublisher
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewJianshuPublisher(task *TaskParams, cfg *config.Config, logger *log.Logger) PublisherInerface {
|
func NewJianshuPublisher(ctx context.Context, task *TaskParams, cfg *config.Config, logger *log.Logger) PublisherInerface {
|
||||||
return &JianshuPublisher{NewBasePublisher(task, cfg, logger)}
|
return &JianshuPublisher{NewBasePublisher(ctx, task, cfg, logger)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *JianshuPublisher) CheckLogin() (bool, string) {
|
func (p *JianshuPublisher) CheckLogin() (bool, string) {
|
||||||
|
|
@ -304,7 +305,7 @@ func (p *JianshuPublisher) PublishNote() (bool, string) {
|
||||||
if err := p.SetupDriver(); err != nil {
|
if err := p.SetupDriver(); err != nil {
|
||||||
return false, fmt.Sprintf("浏览器启动失败: %v", err)
|
return false, fmt.Sprintf("浏览器启动失败: %v", err)
|
||||||
}
|
}
|
||||||
defer p.Close()
|
defer p.Page.Close()
|
||||||
|
|
||||||
steps := []struct {
|
steps := []struct {
|
||||||
name string
|
name string
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package publisher
|
package publisher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"geo/internal/config"
|
"geo/internal/config"
|
||||||
"log"
|
"log"
|
||||||
|
|
@ -15,8 +16,8 @@ type SohuPublisher struct {
|
||||||
*BasePublisher
|
*BasePublisher
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSohuPublisher(task *TaskParams, cfg *config.Config, logger *log.Logger) PublisherInerface {
|
func NewSohuPublisher(ctx context.Context, task *TaskParams, cfg *config.Config, logger *log.Logger) PublisherInerface {
|
||||||
return &SohuPublisher{NewBasePublisher(task, cfg, logger)}
|
return &SohuPublisher{NewBasePublisher(ctx, task, cfg, logger)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *SohuPublisher) CheckLogin() (bool, string) {
|
func (p *SohuPublisher) CheckLogin() (bool, string) {
|
||||||
|
|
@ -487,7 +488,7 @@ func (p *SohuPublisher) PublishNote() (bool, string) {
|
||||||
if err := p.SetupDriver(); err != nil {
|
if err := p.SetupDriver(); err != nil {
|
||||||
return false, fmt.Sprintf("浏览器启动失败: %v", err)
|
return false, fmt.Sprintf("浏览器启动失败: %v", err)
|
||||||
}
|
}
|
||||||
defer p.Close()
|
defer p.Page.Close()
|
||||||
|
|
||||||
steps := []struct {
|
steps := []struct {
|
||||||
name string
|
name string
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package publisher
|
package publisher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"geo/internal/config"
|
"geo/internal/config"
|
||||||
|
|
@ -17,9 +18,9 @@ type ShipinhaoVideoPublisher struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewShipinhaoVideoPublisher 创建视频号发布器
|
// NewShipinhaoVideoPublisher 创建视频号发布器
|
||||||
func NewShipinhaoVideoPublisher(task *TaskParams, config *config.Config, logger *log.Logger) PublisherInerface {
|
func NewShipinhaoVideoPublisher(ctx context.Context, task *TaskParams, config *config.Config, logger *log.Logger) PublisherInerface {
|
||||||
return &ShipinhaoVideoPublisher{
|
return &ShipinhaoVideoPublisher{
|
||||||
BasePublisher: NewBasePublisher(task, config, logger),
|
BasePublisher: NewBasePublisher(ctx, task, config, logger),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -31,7 +32,7 @@ func (p *ShipinhaoVideoPublisher) PublishNote() (bool, string) {
|
||||||
if err := p.SetupDriver(); err != nil {
|
if err := p.SetupDriver(); err != nil {
|
||||||
return false, fmt.Sprintf("浏览器启动失败: %v", err)
|
return false, fmt.Sprintf("浏览器启动失败: %v", err)
|
||||||
}
|
}
|
||||||
|
defer p.Page.Close()
|
||||||
// 3. 加载 cookies 并检查登录状态
|
// 3. 加载 cookies 并检查登录状态
|
||||||
if err := p.LoadCookies(); err == nil {
|
if err := p.LoadCookies(); err == nil {
|
||||||
p.Page.Navigate(p.EditorURL)
|
p.Page.Navigate(p.EditorURL)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package publisher
|
package publisher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"geo/internal/config"
|
"geo/internal/config"
|
||||||
"log"
|
"log"
|
||||||
|
|
@ -16,8 +17,8 @@ type ToutiaoPublisher struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewToutiaoPublisher 构造函数
|
// NewToutiaoPublisher 构造函数
|
||||||
func NewToutiaoPublisher(task *TaskParams, cfg *config.Config, logger *log.Logger) PublisherInerface {
|
func NewToutiaoPublisher(ctx context.Context, task *TaskParams, cfg *config.Config, logger *log.Logger) PublisherInerface {
|
||||||
return &ToutiaoPublisher{NewBasePublisher(task, cfg, logger)}
|
return &ToutiaoPublisher{NewBasePublisher(ctx, task, cfg, logger)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ToutiaoPublisher) CheckLogin() (bool, string) {
|
func (p *ToutiaoPublisher) CheckLogin() (bool, string) {
|
||||||
|
|
@ -472,7 +473,7 @@ func (p *ToutiaoPublisher) PublishNote() (bool, string) {
|
||||||
if err := p.SetupDriver(); err != nil {
|
if err := p.SetupDriver(); err != nil {
|
||||||
return false, fmt.Sprintf("浏览器启动失败: %v", err)
|
return false, fmt.Sprintf("浏览器启动失败: %v", err)
|
||||||
}
|
}
|
||||||
defer p.Close()
|
defer p.Page.Close()
|
||||||
|
|
||||||
// 执行发布流程
|
// 执行发布流程
|
||||||
steps := []struct {
|
steps := []struct {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package publisher
|
package publisher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"geo/internal/config"
|
"geo/internal/config"
|
||||||
"log"
|
"log"
|
||||||
|
|
@ -19,9 +20,9 @@ type WangyiPublisher struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWangyiPublisher 构造函数
|
// NewWangyiPublisher 构造函数
|
||||||
func NewWangyiPublisher(task *TaskParams, cfg *config.Config, logger *log.Logger) PublisherInerface {
|
func NewWangyiPublisher(ctx context.Context, task *TaskParams, cfg *config.Config, logger *log.Logger) PublisherInerface {
|
||||||
return &WangyiPublisher{
|
return &WangyiPublisher{
|
||||||
BasePublisher: NewBasePublisher(task, cfg, logger),
|
BasePublisher: NewBasePublisher(ctx, task, cfg, logger),
|
||||||
Category: "",
|
Category: "",
|
||||||
IsOriginal: true,
|
IsOriginal: true,
|
||||||
}
|
}
|
||||||
|
|
@ -33,7 +34,7 @@ func (p *WangyiPublisher) CheckLogin() (bool, string) {
|
||||||
if err := p.SetupDriver(); err != nil {
|
if err := p.SetupDriver(); err != nil {
|
||||||
return false, fmt.Sprintf("浏览器启动失败: %v", err)
|
return false, fmt.Sprintf("浏览器启动失败: %v", err)
|
||||||
}
|
}
|
||||||
defer p.Close()
|
defer p.Page.Close()
|
||||||
|
|
||||||
p.Page.MustNavigate(p.EditorURL)
|
p.Page.MustNavigate(p.EditorURL)
|
||||||
p.Sleep(3)
|
p.Sleep(3)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package publisher
|
package publisher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"geo/internal/config"
|
"geo/internal/config"
|
||||||
"log"
|
"log"
|
||||||
|
|
@ -16,8 +17,8 @@ type XiaohongshuPublisher struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewXiaohongshuPublisher 构造函数,增加 logger 参数
|
// NewXiaohongshuPublisher 构造函数,增加 logger 参数
|
||||||
func NewXiaohongshuPublisher(task *TaskParams, cfg *config.Config, logger *log.Logger) PublisherInerface {
|
func NewXiaohongshuPublisher(ctx context.Context, task *TaskParams, cfg *config.Config, logger *log.Logger) PublisherInerface {
|
||||||
return &XiaohongshuPublisher{NewBasePublisher(task, cfg, logger)}
|
return &XiaohongshuPublisher{NewBasePublisher(ctx, task, cfg, logger)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *XiaohongshuPublisher) CheckLogin() (bool, string) {
|
func (p *XiaohongshuPublisher) CheckLogin() (bool, string) {
|
||||||
|
|
@ -394,7 +395,6 @@ func (p *XiaohongshuPublisher) ClickUploadBotton() error {
|
||||||
} else if len(buttons) > 0 {
|
} else if len(buttons) > 0 {
|
||||||
if err := p.JSClick(buttons[0]); err != nil {
|
if err := p.JSClick(buttons[0]); err != nil {
|
||||||
return fmt.Errorf("JS点击按钮失败: %v", err)
|
return fmt.Errorf("JS点击按钮失败: %v", err)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
p.LogInfo("已点击上传按钮")
|
p.LogInfo("已点击上传按钮")
|
||||||
p.Sleep(1)
|
p.Sleep(1)
|
||||||
|
|
@ -427,7 +427,7 @@ func (p *XiaohongshuPublisher) PublishNote() (bool, string) {
|
||||||
if err := p.SetupDriver(); err != nil {
|
if err := p.SetupDriver(); err != nil {
|
||||||
return false, fmt.Sprintf("浏览器启动失败: %v", err)
|
return false, fmt.Sprintf("浏览器启动失败: %v", err)
|
||||||
}
|
}
|
||||||
defer p.Close()
|
defer p.Page.Close()
|
||||||
|
|
||||||
// 执行发布流程
|
// 执行发布流程
|
||||||
steps := []struct {
|
steps := []struct {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package publisher
|
package publisher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"geo/internal/config"
|
"geo/internal/config"
|
||||||
"log"
|
"log"
|
||||||
|
|
@ -19,9 +20,9 @@ type XiaohongshuVideoPublisher struct {
|
||||||
longWait int
|
longWait int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewXiaohongshuVideoPublisher(task *TaskParams, cfg *config.Config, logger *log.Logger) PublisherInerface {
|
func NewXiaohongshuVideoPublisher(ctx context.Context, task *TaskParams, cfg *config.Config, logger *log.Logger) PublisherInerface {
|
||||||
return &XiaohongshuVideoPublisher{
|
return &XiaohongshuVideoPublisher{
|
||||||
BasePublisher: NewBasePublisher(task, cfg, logger),
|
BasePublisher: NewBasePublisher(ctx, task, cfg, logger),
|
||||||
shortWait: 1,
|
shortWait: 1,
|
||||||
mediumWait: 3,
|
mediumWait: 3,
|
||||||
longWait: 5,
|
longWait: 5,
|
||||||
|
|
@ -34,7 +35,7 @@ func (p *XiaohongshuVideoPublisher) CheckLogin() (bool, string) {
|
||||||
if err := p.SetupDriver(); err != nil {
|
if err := p.SetupDriver(); err != nil {
|
||||||
return false, fmt.Sprintf("浏览器启动失败: %v", err)
|
return false, fmt.Sprintf("浏览器启动失败: %v", err)
|
||||||
}
|
}
|
||||||
defer p.Close()
|
defer p.Page.Close()
|
||||||
|
|
||||||
p.Page.MustNavigate(p.LoginedURL)
|
p.Page.MustNavigate(p.LoginedURL)
|
||||||
p.Sleep(3)
|
p.Sleep(3)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package publisher
|
package publisher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"geo/internal/config"
|
"geo/internal/config"
|
||||||
"log"
|
"log"
|
||||||
|
|
@ -15,8 +16,8 @@ type ZhihuPublisher struct {
|
||||||
*BasePublisher
|
*BasePublisher
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewZhihuPublisher(task *TaskParams, cfg *config.Config, logger *log.Logger) PublisherInerface {
|
func NewZhihuPublisher(ctx context.Context, task *TaskParams, cfg *config.Config, logger *log.Logger) PublisherInerface {
|
||||||
return &ZhihuPublisher{NewBasePublisher(task, cfg, logger)}
|
return &ZhihuPublisher{NewBasePublisher(ctx, task, cfg, logger)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ZhihuPublisher) CheckLogin() (bool, string) {
|
func (p *ZhihuPublisher) CheckLogin() (bool, string) {
|
||||||
|
|
@ -25,7 +26,7 @@ func (p *ZhihuPublisher) CheckLogin() (bool, string) {
|
||||||
if err := p.SetupDriver(); err != nil {
|
if err := p.SetupDriver(); err != nil {
|
||||||
return false, fmt.Sprintf("浏览器启动失败: %v", err)
|
return false, fmt.Sprintf("浏览器启动失败: %v", err)
|
||||||
}
|
}
|
||||||
defer p.Close()
|
defer p.Page.Close()
|
||||||
|
|
||||||
p.Page.MustNavigate(p.EditorURL)
|
p.Page.MustNavigate(p.EditorURL)
|
||||||
p.Sleep(3)
|
p.Sleep(3)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,143 @@
|
||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-rod/rod"
|
||||||
|
"github.com/go-rod/rod/lib/launcher"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMultipleChromeProcesses(t *testing.T) {
|
||||||
|
browsers := make([]*rod.Browser, 5)
|
||||||
|
|
||||||
|
// 启动 5 个独立的 Chrome 进程
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
browsers[i] = rod.New().MustConnect()
|
||||||
|
defer browsers[i].MustClose()
|
||||||
|
|
||||||
|
page := browsers[i].MustPage("https://example.com")
|
||||||
|
title := page.MustInfo().Title
|
||||||
|
fmt.Printf("进程 %d: %s\n", i, title)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开任务管理器,可以看到 5 个 chrome.exe 进程
|
||||||
|
time.Sleep(10 * time.Minute)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestCustomChromeWithMixedHeadless 使用自定义Chrome浏览器,启动5个进程(偶数有头,奇数无头)
|
||||||
|
func TestCustomChromeWithMixedHeadless(t *testing.T) {
|
||||||
|
// 配置你的Chrome路径
|
||||||
|
chromePath := "D:\\gop\\geoGo\\chrome\\chrome.exe"
|
||||||
|
|
||||||
|
processCount := 5
|
||||||
|
browsers := make([]*rod.Browser, processCount)
|
||||||
|
launchers := make([]*launcher.Launcher, processCount)
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
t.Logf("开始启动 %d 个 Chrome 进程(偶数索引有头,奇数索引无头)...", processCount)
|
||||||
|
|
||||||
|
for i := 0; i < processCount; i++ {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(idx int) {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
|
// 偶数(0,2,4):有头模式,奇数(1,3):无头模式
|
||||||
|
headless := (idx%2 != 0) // 奇数无头,偶数有头
|
||||||
|
|
||||||
|
// 每个进程使用独立的用户数据目录
|
||||||
|
userDataDir := fmt.Sprintf("./chrome_data/user_%d_%d", idx, time.Now().UnixNano())
|
||||||
|
|
||||||
|
t.Logf("[进程 %d] 启动中,headless=%v, userDataDir=%s", idx, headless, userDataDir)
|
||||||
|
|
||||||
|
// 创建 launcher
|
||||||
|
l := launcher.New().
|
||||||
|
Bin(chromePath).
|
||||||
|
UserDataDir(userDataDir).
|
||||||
|
Headless(headless).
|
||||||
|
Leakless(false)
|
||||||
|
|
||||||
|
// 有头模式需要额外配置
|
||||||
|
if !headless {
|
||||||
|
l.Set("window-size", "1920,1080")
|
||||||
|
l.Set("start-maximized")
|
||||||
|
// 移除 headless 相关参数
|
||||||
|
l.Delete("headless")
|
||||||
|
} else {
|
||||||
|
// 无头模式优化
|
||||||
|
l.Set("disable-gpu")
|
||||||
|
l.Set("no-sandbox")
|
||||||
|
l.Set("disable-dev-shm-usage")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 启动浏览器进程
|
||||||
|
url, err := l.Launch()
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("[进程 %d] ❌ 启动失败: %v", idx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 连接到浏览器
|
||||||
|
browser := rod.New().ControlURL(url).MustConnect()
|
||||||
|
|
||||||
|
browsers[idx] = browser
|
||||||
|
launchers[idx] = l
|
||||||
|
|
||||||
|
// 创建测试页面验证
|
||||||
|
page := browser.MustPage("about:blank")
|
||||||
|
|
||||||
|
// 获取浏览器版本
|
||||||
|
version, err := browser.Version()
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("[进程 %d] 获取版本失败: %v", idx, err)
|
||||||
|
} else {
|
||||||
|
mode := "有头"
|
||||||
|
if headless {
|
||||||
|
mode = "无头"
|
||||||
|
}
|
||||||
|
t.Logf("[进程 %d] ✅ 启动成功 | 模式: %s | 协议版本: %s | PID: %d",
|
||||||
|
idx, mode, version.ProtocolVersion, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 有头模式:打开百度可见
|
||||||
|
if !headless {
|
||||||
|
page.MustNavigate("https://www.baidu.com")
|
||||||
|
t.Logf("[进程 %d] 有头模式已打开百度页面,可见浏览器窗口", idx)
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
} else {
|
||||||
|
page.MustNavigate("https://www.example.com")
|
||||||
|
t.Logf("[进程 %d] 无头模式已访问 example.com(不可见)", idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
page.MustClose()
|
||||||
|
}(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 等待所有进程启动
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
// 验证启动结果
|
||||||
|
successCount := 0
|
||||||
|
for i, browser := range browsers {
|
||||||
|
if browser != nil {
|
||||||
|
successCount++
|
||||||
|
t.Logf("[进程 %d] 运行中", i)
|
||||||
|
} else {
|
||||||
|
t.Logf("[进程 %d] 启动失败", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("成功启动 %d/%d 个 Chrome 进程", successCount, processCount)
|
||||||
|
t.Log("浏览器窗口已打开(有头模式可见),按 Enter 键关闭所有进程...")
|
||||||
|
fmt.Scanln()
|
||||||
|
|
||||||
|
// 清理
|
||||||
|
//for i, browser := range browsers {
|
||||||
|
// if browser != nil {
|
||||||
|
// browser.MustClose()
|
||||||
|
// t.Logf("[进程 %d] 已关闭", i)
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
@ -58,7 +58,7 @@ func (s *LoginService) LoginPlatform(c *fiber.Ctx, req *entitys.LoginPlatformReq
|
||||||
LoginUrl: platInfo.LoginURL,
|
LoginUrl: platInfo.LoginURL,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
pub := publisherClass.InitMethod(task, s.cfg, nil)
|
pub := publisherClass.InitMethod(c.UserContext(), task, s.cfg, nil)
|
||||||
success, msg := pub.WaitLogin()
|
success, msg := pub.WaitLogin()
|
||||||
if !success {
|
if !success {
|
||||||
return errcode.SysErr(msg)
|
return errcode.SysErr(msg)
|
||||||
|
|
|
||||||
|
|
@ -156,7 +156,7 @@ func (s *PublishService) PublishExecuteRetry(c *fiber.Ctx, req *entitys.PublishE
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
result := pm.RetryTask(req.RequestID)
|
result := pm.RetryTask(c.UserContext(), req.RequestID)
|
||||||
return pkg.HandleResponse(c, result)
|
return pkg.HandleResponse(c, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,485 @@
|
||||||
|
GOROOT=D:\go #gosetup
|
||||||
|
GOPATH=D:\go #gosetup
|
||||||
|
D:\go\bin\go.exe build -o C:\Users\Administrator\AppData\Local\JetBrains\GoLand2025.2\tmp\GoLand\___go_build_geo_cmd_server.exe -gcflags "all=-N -l" geo/cmd/server #gosetup
|
||||||
|
warning: both GOPATH and GOROOT are the same directory (D:\go); see https://go.dev/wiki/InstallTroubleshooting
|
||||||
|
"D:\GoLand 2025.2.5\plugins\go-plugin\lib\dlv\windows\dlv.exe" --listen=127.0.0.1:62082 --headless=true --api-version=2 --check-go-version=false --only-same-user=false exec C:\Users\Administrator\AppData\Local\JetBrains\GoLand2025.2\tmp\GoLand\___go_build_geo_cmd_server.exe -- #gosetup
|
||||||
|
API server listening at: 127.0.0.1:62082
|
||||||
|
WARNING: undefined behavior - version of Delve is too old for Go version go1.26.1 (maximum supported version 1.25)
|
||||||
|
|
||||||
|
┌───────────────────────────────────────────────────┐
|
||||||
|
│ Fiber v2.52.12 │
|
||||||
|
│ http://127.0.0.1:5001 │
|
||||||
|
│ (bound on host 0.0.0.0 and port 5001) │
|
||||||
|
│ │
|
||||||
|
│ Handlers ............ 17 Processes ........... 1 │
|
||||||
|
│ Prefork ....... Disabled PID ............. 22108 │
|
||||||
|
└───────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
|
||||||
|
2026/04/10 16:52:53 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
|
||||||
|
[423.550ms] [rows:1] SELECT * FROM `token` WHERE access_token='6cb55ce2-2556-4908-91b5-5b78f0168cce' AND status=1 LIMIT 1
|
||||||
|
token
|
||||||
|
16:52:53 | 200 | 424.6891ms | 127.0.0.1 | POST | /publish_on | -
|
||||||
|
2026/04/10 16:52:53 自动发布服务已启动,tokenID=1,worker数量=3
|
||||||
|
2026/04/10 16:52:53 [Worker-1] 启动,tokenID=1
|
||||||
|
2026/04/10 16:52:53 [Worker-2] 启动,tokenID=1
|
||||||
|
2026/04/10 16:52:53 [Worker-0] 启动,tokenID=1
|
||||||
|
|
||||||
|
2026/04/10 16:52:54 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
|
||||||
|
[412.746ms] [rows:1]
|
||||||
|
UPDATE publish p
|
||||||
|
SET p.status = 2,uid='cd76b1df-df01-4a'
|
||||||
|
WHERE p.request_id = (
|
||||||
|
SELECT request_id FROM (
|
||||||
|
SELECT p2.request_id
|
||||||
|
FROM publish p2
|
||||||
|
INNER JOIN plat pl ON p2.plat_index COLLATE utf8mb4_unicode_ci = pl.index
|
||||||
|
WHERE p2.token_id = 1
|
||||||
|
AND p2.status = 1
|
||||||
|
AND p2.publish_time <= '2026-04-10 16:52:53'
|
||||||
|
AND pl.status = 1
|
||||||
|
ORDER BY p2.publish_time ASC
|
||||||
|
LIMIT 1
|
||||||
|
) AS tmp
|
||||||
|
)
|
||||||
|
AND p.status = 1
|
||||||
|
|
||||||
|
publish
|
||||||
|
|
||||||
|
2026/04/10 16:52:54 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
|
||||||
|
[418.524ms] [rows:1]
|
||||||
|
UPDATE publish p
|
||||||
|
SET p.status = 2,uid='f2a6982a-8bef-4e'
|
||||||
|
WHERE p.request_id = (
|
||||||
|
SELECT request_id FROM (
|
||||||
|
SELECT p2.request_id
|
||||||
|
FROM publish p2
|
||||||
|
INNER JOIN plat pl ON p2.plat_index COLLATE utf8mb4_unicode_ci = pl.index
|
||||||
|
WHERE p2.token_id = 1
|
||||||
|
AND p2.status = 1
|
||||||
|
AND p2.publish_time <= '2026-04-10 16:52:53'
|
||||||
|
AND pl.status = 1
|
||||||
|
ORDER BY p2.publish_time ASC
|
||||||
|
LIMIT 1
|
||||||
|
) AS tmp
|
||||||
|
)
|
||||||
|
AND p.status = 1
|
||||||
|
|
||||||
|
publish
|
||||||
|
|
||||||
|
2026/04/10 16:52:54 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
|
||||||
|
[425.694ms] [rows:1]
|
||||||
|
UPDATE publish p
|
||||||
|
SET p.status = 2,uid='eba6d8a6-88c3-49'
|
||||||
|
WHERE p.request_id = (
|
||||||
|
SELECT request_id FROM (
|
||||||
|
SELECT p2.request_id
|
||||||
|
FROM publish p2
|
||||||
|
INNER JOIN plat pl ON p2.plat_index COLLATE utf8mb4_unicode_ci = pl.index
|
||||||
|
WHERE p2.token_id = 1
|
||||||
|
AND p2.status = 1
|
||||||
|
AND p2.publish_time <= '2026-04-10 16:52:53'
|
||||||
|
AND pl.status = 1
|
||||||
|
ORDER BY p2.publish_time ASC
|
||||||
|
LIMIT 1
|
||||||
|
) AS tmp
|
||||||
|
)
|
||||||
|
AND p.status = 1
|
||||||
|
|
||||||
|
publish
|
||||||
|
|
||||||
|
2026/04/10 16:52:54 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
|
||||||
|
[391.244ms] [rows:1]
|
||||||
|
SELECT
|
||||||
|
p.request_id,
|
||||||
|
p.plat_index,
|
||||||
|
p.title,
|
||||||
|
p.tag,
|
||||||
|
p.user_index,
|
||||||
|
p.url,
|
||||||
|
p.img,
|
||||||
|
p.publish_time,
|
||||||
|
p.status,
|
||||||
|
pl.index as plat_index_value,
|
||||||
|
pl.status as plat_status,
|
||||||
|
pl.login_url,
|
||||||
|
pl.edit_url,
|
||||||
|
pl.logined_url,
|
||||||
|
pl.desc
|
||||||
|
FROM publish p
|
||||||
|
INNER JOIN plat pl ON p.plat_index COLLATE utf8mb4_unicode_ci = pl.index AND pl.status = 1
|
||||||
|
WHERE uid='cd76b1df-df01-4a' AND p.token_id = 1
|
||||||
|
ORDER BY p.publish_time DESC
|
||||||
|
LIMIT 1
|
||||||
|
|
||||||
|
publish
|
||||||
|
2026/04/10 16:52:54.478724 ================================================================================
|
||||||
|
2026/04/10 16:52:54.478724 任务开始 | RequestID: 6 | 时间: 2026-04-10 16:52:54.478
|
||||||
|
2026/04/10 16:52:54.478724 ================================================================================
|
||||||
|
2026/04/10 16:52:54.478724 [任务 6] 开始处理(headless=true)
|
||||||
|
2026/04/10 16:52:54.478724 [任务 6] 任务详情 - 平台:zh,标题:地推看过来!!!,用户:0d86b848uu2183uu4a08
|
||||||
|
2026/04/10 16:52:54.478724 [任务 6] 标签解析完成: [#地推 #四川地推 #创业]
|
||||||
|
2026/04/10 16:52:54.478724 [任务 6] 开始下载文档...
|
||||||
|
2026/04/10 16:52:54 [Worker-1] 开始处理任务 requestID=6
|
||||||
|
|
||||||
|
2026/04/10 16:52:54 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
|
||||||
|
[406.859ms] [rows:1]
|
||||||
|
SELECT
|
||||||
|
p.request_id,
|
||||||
|
p.plat_index,
|
||||||
|
p.title,
|
||||||
|
p.tag,
|
||||||
|
p.user_index,
|
||||||
|
p.url,
|
||||||
|
p.img,
|
||||||
|
p.publish_time,
|
||||||
|
p.status,
|
||||||
|
pl.index as plat_index_value,
|
||||||
|
pl.status as plat_status,
|
||||||
|
pl.login_url,
|
||||||
|
pl.edit_url,
|
||||||
|
pl.logined_url,
|
||||||
|
pl.desc
|
||||||
|
FROM publish p
|
||||||
|
INNER JOIN plat pl ON p.plat_index COLLATE utf8mb4_unicode_ci = pl.index AND pl.status = 1
|
||||||
|
WHERE uid='f2a6982a-8bef-4e' AND p.token_id = 1
|
||||||
|
ORDER BY p.publish_time DESC
|
||||||
|
LIMIT 1
|
||||||
|
|
||||||
|
publish
|
||||||
|
2026/04/10 16:52:54.499312 ================================================================================
|
||||||
|
2026/04/10 16:52:54.499312 任务开始 | RequestID: 4 | 时间: 2026-04-10 16:52:54.499
|
||||||
|
2026/04/10 16:52:54.499312 ================================================================================
|
||||||
|
2026/04/10 16:52:54.499840 [任务 4] 开始处理(headless=true)
|
||||||
|
2026/04/10 16:52:54.499840 [任务 4] 任务详情 - 平台:xhssp,标题:萌妹,用户:0d86b848uu2183uu4a08
|
||||||
|
2026/04/10 16:52:54.499840 [任务 4] 标签解析完成: [萌妹 宅舞 超性感]
|
||||||
|
2026/04/10 16:52:54.499840 [任务 4] 开始下载文档...
|
||||||
|
|
||||||
|
2026/04/10 16:52:54 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
|
||||||
|
[401.220ms] [rows:1]
|
||||||
|
SELECT
|
||||||
|
p.request_id,
|
||||||
|
p.plat_index,
|
||||||
|
p.title,
|
||||||
|
p.tag,
|
||||||
|
p.user_index,
|
||||||
|
p.url,
|
||||||
|
p.img,
|
||||||
|
p.publish_time,
|
||||||
|
p.status,
|
||||||
|
pl.index as plat_index_value,
|
||||||
|
pl.status as plat_status,
|
||||||
|
pl.login_url,
|
||||||
|
pl.edit_url,
|
||||||
|
pl.logined_url,
|
||||||
|
pl.desc
|
||||||
|
FROM publish p
|
||||||
|
INNER JOIN plat pl ON p.plat_index COLLATE utf8mb4_unicode_ci = pl.index AND pl.status = 1
|
||||||
|
WHERE uid='eba6d8a6-88c3-49' AND p.token_id = 1
|
||||||
|
ORDER BY p.publish_time DESC
|
||||||
|
LIMIT 1
|
||||||
|
|
||||||
|
publish
|
||||||
|
2026/04/10 16:52:54.501413 ================================================================================
|
||||||
|
2026/04/10 16:52:54.501413 任务开始 | RequestID: 5 | 时间: 2026-04-10 16:52:54.501
|
||||||
|
2026/04/10 16:52:54.501413 ================================================================================
|
||||||
|
2026/04/10 16:52:54.501413 [任务 5] 开始处理(headless=true)
|
||||||
|
2026/04/10 16:52:54.501413 [任务 5] 任务详情 - 平台:sphsp,标题:盘点全网最火的meme原型,用户:0d86b848uu2183uu4a08
|
||||||
|
2026/04/10 16:52:54.501413 [任务 5] 标签解析完成: [猫 meme 万恶之源]
|
||||||
|
2026/04/10 16:52:54.501413 [任务 5] 开始下载文档...
|
||||||
|
2026/04/10 16:52:54 [Worker-2] 开始处理任务 requestID=4
|
||||||
|
2026/04/10 16:52:54 [Worker-0] 开始处理任务 requestID=5
|
||||||
|
2026/04/10 16:52:54.568721 [任务 6] ✅ 文档下载成功: D:\gop\geoGo\docs\6.docx
|
||||||
|
2026/04/10 16:52:54.569769 [任务 6] 开始下载图片...
|
||||||
|
2026/04/10 16:52:54.629638 [任务 6] ✅ 图片下载成功: D:\gop\geoGo\images\6_1e3dcdb4-0f8a-4b57-aac2-85ecff03ff12.jpg
|
||||||
|
2026/04/10 16:52:55.723048 [任务 4] ✅ 文档下载成功: D:\gop\geoGo\docs\4.mp4
|
||||||
|
2026/04/10 16:52:55.723048 [任务 4] 开始下载图片...
|
||||||
|
2026/04/10 16:52:56.014721 [任务 5] ✅ 文档下载成功: D:\gop\geoGo\docs\5.mp4
|
||||||
|
2026/04/10 16:52:56.015773 [任务 5] 开始下载图片...
|
||||||
|
2026/04/10 16:52:56.206874 [任务 5] ✅ 图片下载成功: D:\gop\geoGo\images\5_003e4110-e937-491f-8cf2-92df3de00a8c.png
|
||||||
|
2026/04/10 16:52:56.206874 [任务 5] 开始执行发布...
|
||||||
|
2026/04/10 16:52:56.206874 📌 ==================================================
|
||||||
|
2026/04/10 16:52:56.206874 📌 开始执行:sphsp
|
||||||
|
2026/04/10 16:52:56.206874 📌 标题: 盘点全网最火的meme原型
|
||||||
|
2026/04/10 16:52:56.206874 📌 标签: [猫 meme 万恶之源]
|
||||||
|
2026/04/10 16:52:56.206874 📌 ==================================================
|
||||||
|
2026/04/10 16:52:56.206874 📌 初始化浏览器。。。。
|
||||||
|
2026/04/10 16:52:56.233002 [任务 4] ✅ 图片下载成功: D:\gop\geoGo\images\4_769c6040-bff9-472b-9b9c-33d8f74cf61f.png
|
||||||
|
2026/04/10 16:52:56.233002 [任务 4] 开始执行发布...
|
||||||
|
2026/04/10 16:52:56.233002 📌 ==================================================
|
||||||
|
2026/04/10 16:52:56.233002 📌 开始执行:xhssp
|
||||||
|
2026/04/10 16:52:56.233002 📌 标题: 萌妹
|
||||||
|
2026/04/10 16:52:56.233002 📌 标签: [萌妹 宅舞 超性感]
|
||||||
|
2026/04/10 16:52:56.233002 📌 ==================================================
|
||||||
|
2026/04/10 16:52:56.233002 📌 初始化浏览器。。。。
|
||||||
|
2026/04/10 16:52:56.907120 [任务 6] 开始提取文档内容...
|
||||||
|
2026/04/10 16:52:58.614081 [任务 6] ✅ 内容提取成功,长度: 69
|
||||||
|
2026/04/10 16:52:58.614081 [任务 6] 开始执行发布...
|
||||||
|
2026/04/10 16:52:58.614081 📌 ==================================================
|
||||||
|
2026/04/10 16:52:58.614081 📌 开始执行:zh
|
||||||
|
2026/04/10 16:52:58.614081 📌 标题: 地推看过来!!!
|
||||||
|
2026/04/10 16:52:58.614081 📌 标签: [#地推 #四川地推 #创业]
|
||||||
|
2026/04/10 16:52:58.614081 📌 ==================================================
|
||||||
|
2026/04/10 16:52:58.614081 📌 初始化浏览器。。。。
|
||||||
|
2026/04/10 16:52:58.616804 ✅ 初始化页面: 成功
|
||||||
|
2026/04/10 16:52:59.468517 [任务 5] ❌ 发布失败: 需要登录
|
||||||
|
2026/04/10 16:52:59.617059 📌 开始上传视频: D:\gop\geoGo\docs\4.mp4
|
||||||
|
2026/04/10 16:52:59.646726 📌 视频文件已选择: D:\gop\geoGo\docs\4.mp4
|
||||||
|
2026/04/10 16:52:59.646726 📌 等待视频上传完成...
|
||||||
|
|
||||||
|
2026/04/10 16:52:59 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
|
||||||
|
[429.171ms] [rows:1] UPDATE publish SET status = 3, msg = '需要登录' WHERE token_id=1 AND request_id = '5'
|
||||||
|
publish
|
||||||
|
2026/04/10 16:52:59.897687 ================================================================================
|
||||||
|
2026/04/10 16:52:59.897687 任务结束 | RequestID: 5 | 结果: false
|
||||||
|
2026/04/10 16:52:59.898712 [任务 5] 已删除文档文件: D:\gop\geoGo\docs\5.mp4
|
||||||
|
2026/04/10 16:52:59.899367 [任务 5] 已删除图片文件: D:\gop\geoGo\images\5_003e4110-e937-491f-8cf2-92df3de00a8c.png
|
||||||
|
2026/04/10 16:52:59 [Worker-0] 任务失败: 需要登录
|
||||||
|
2026/04/10 16:53:00.050108 📌 发布按钮已可点击,视频上传完成
|
||||||
|
2026/04/10 16:53:00.050108 ✅ 上传视频: 成功
|
||||||
|
2026/04/10 16:53:01.050256 📌 输入视频标题: 萌妹
|
||||||
|
2026/04/10 16:53:01.755888 📌 未登录或登录已过期,需要重新登录
|
||||||
|
2026/04/10 16:53:01.755888 ❌ 初始化页面: 失败 需要登录
|
||||||
|
2026/04/10 16:53:01.779792 [任务 6] ❌ 发布失败: 初始化页面失败: 需要登录
|
||||||
|
|
||||||
|
2026/04/10 16:53:02 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
|
||||||
|
[427.718ms] [rows:1] UPDATE publish SET status = 3, msg = '初始化页面失败: 需要登录' WHERE token_id=1 AND request_id = '6'
|
||||||
|
publish
|
||||||
|
2026/04/10 16:53:02.207510 ================================================================================
|
||||||
|
2026/04/10 16:53:02.207510 任务结束 | RequestID: 6 | 结果: false
|
||||||
|
2026/04/10 16:53:02.208014 [任务 6] 已删除文档文件: D:\gop\geoGo\docs\6.docx
|
||||||
|
2026/04/10 16:53:02.208014 [任务 6] 已删除图片文件: D:\gop\geoGo\images\6_1e3dcdb4-0f8a-4b57-aac2-85ecff03ff12.jpg
|
||||||
|
2026/04/10 16:53:02 [Worker-1] 任务失败: 初始化页面失败: 需要登录
|
||||||
|
|
||||||
|
2026/04/10 16:53:02 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
|
||||||
|
[406.214ms] [rows:1]
|
||||||
|
UPDATE publish p
|
||||||
|
SET p.status = 2,uid='e3a191eb-07d2-48'
|
||||||
|
WHERE p.request_id = (
|
||||||
|
SELECT request_id FROM (
|
||||||
|
SELECT p2.request_id
|
||||||
|
FROM publish p2
|
||||||
|
INNER JOIN plat pl ON p2.plat_index COLLATE utf8mb4_unicode_ci = pl.index
|
||||||
|
WHERE p2.token_id = 1
|
||||||
|
AND p2.status = 1
|
||||||
|
AND p2.publish_time <= '2026-04-10 16:53:01'
|
||||||
|
AND pl.status = 1
|
||||||
|
ORDER BY p2.publish_time ASC
|
||||||
|
LIMIT 1
|
||||||
|
) AS tmp
|
||||||
|
)
|
||||||
|
AND p.status = 1
|
||||||
|
|
||||||
|
publish
|
||||||
|
2026/04/10 16:53:02.529767 ❌ 输入标题: 失败 未找到标题输入框
|
||||||
|
2026/04/10 16:53:02.529767 [任务 4] ❌ 发布失败: 输入标题失败: 未找到标题输入框
|
||||||
|
|
||||||
|
2026/04/10 16:53:02 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
|
||||||
|
[379.609ms] [rows:1]
|
||||||
|
SELECT
|
||||||
|
p.request_id,
|
||||||
|
p.plat_index,
|
||||||
|
p.title,
|
||||||
|
p.tag,
|
||||||
|
p.user_index,
|
||||||
|
p.url,
|
||||||
|
p.img,
|
||||||
|
p.publish_time,
|
||||||
|
p.status,
|
||||||
|
pl.index as plat_index_value,
|
||||||
|
pl.status as plat_status,
|
||||||
|
pl.login_url,
|
||||||
|
pl.edit_url,
|
||||||
|
pl.logined_url,
|
||||||
|
pl.desc
|
||||||
|
FROM publish p
|
||||||
|
INNER JOIN plat pl ON p.plat_index COLLATE utf8mb4_unicode_ci = pl.index AND pl.status = 1
|
||||||
|
WHERE uid='e3a191eb-07d2-48' AND p.token_id = 1
|
||||||
|
ORDER BY p.publish_time DESC
|
||||||
|
LIMIT 1
|
||||||
|
|
||||||
|
publish
|
||||||
|
2026/04/10 16:53:02.686657 ================================================================================
|
||||||
|
2026/04/10 16:53:02.686657 任务开始 | RequestID: 1 | 时间: 2026-04-10 16:53:02.686
|
||||||
|
2026/04/10 16:53:02.686657 ================================================================================
|
||||||
|
2026/04/10 16:53:02.686657 [任务 1] 开始处理(headless=true)
|
||||||
|
2026/04/10 16:53:02.686657 [任务 1] 任务详情 - 平台:xhs,标题:房地产新格局,用户:0d86b848uu2183uu4a08
|
||||||
|
2026/04/10 16:53:02.686657 [任务 1] 标签解析完成: [房地产 房地产格局]
|
||||||
|
2026/04/10 16:53:02.686657 [任务 1] 开始下载文档...
|
||||||
|
2026/04/10 16:53:02 [Worker-0] 开始处理任务 requestID=1
|
||||||
|
2026/04/10 16:53:02.750797 [任务 1] ✅ 文档下载成功: D:\gop\geoGo\docs\1.docx
|
||||||
|
2026/04/10 16:53:02.750797 [任务 1] 开始下载图片...
|
||||||
|
|
||||||
|
2026/04/10 16:53:02 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
|
||||||
|
[445.705ms] [rows:1] UPDATE publish SET status = 3, msg = '输入标题失败: 未找到标题输入框' WHERE token_id=1 AND request_id = '4'
|
||||||
|
publish
|
||||||
|
2026/04/10 16:53:02.975473 ================================================================================
|
||||||
|
2026/04/10 16:53:02.975473 任务结束 | RequestID: 4 | 结果: false
|
||||||
|
2026/04/10 16:53:02.976009 [任务 4] 已删除文档文件: D:\gop\geoGo\docs\4.mp4
|
||||||
|
2026/04/10 16:53:02.976539 [任务 4] 已删除图片文件: D:\gop\geoGo\images\4_769c6040-bff9-472b-9b9c-33d8f74cf61f.png
|
||||||
|
2026/04/10 16:53:02 [Worker-2] 任务失败: 输入标题失败: 未找到标题输入框
|
||||||
|
2026/04/10 16:53:03.042424 [任务 1] ✅ 图片下载成功: D:\gop\geoGo\images\1_9ffe0dd7-108b-455d-aca4-bf729eba7ab9.png
|
||||||
|
2026/04/10 16:53:03.042424 [任务 1] 开始提取文档内容...
|
||||||
|
|
||||||
|
2026/04/10 16:53:04 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
|
||||||
|
[378.221ms] [rows:1]
|
||||||
|
UPDATE publish p
|
||||||
|
SET p.status = 2,uid='5b37ab96-e0de-46'
|
||||||
|
WHERE p.request_id = (
|
||||||
|
SELECT request_id FROM (
|
||||||
|
SELECT p2.request_id
|
||||||
|
FROM publish p2
|
||||||
|
INNER JOIN plat pl ON p2.plat_index COLLATE utf8mb4_unicode_ci = pl.index
|
||||||
|
WHERE p2.token_id = 1
|
||||||
|
AND p2.status = 1
|
||||||
|
AND p2.publish_time <= '2026-04-10 16:53:04'
|
||||||
|
AND pl.status = 1
|
||||||
|
ORDER BY p2.publish_time ASC
|
||||||
|
LIMIT 1
|
||||||
|
) AS tmp
|
||||||
|
)
|
||||||
|
AND p.status = 1
|
||||||
|
|
||||||
|
publish
|
||||||
|
2026/04/10 16:53:04.715720 [任务 1] ✅ 内容提取成功,长度: 5372
|
||||||
|
2026/04/10 16:53:04.715720 [任务 1] 开始执行发布...
|
||||||
|
2026/04/10 16:53:04.715720 📌 ==================================================
|
||||||
|
2026/04/10 16:53:04.715720 📌 开始执行:xhs
|
||||||
|
2026/04/10 16:53:04.715720 📌 标题: 房地产新格局
|
||||||
|
2026/04/10 16:53:04.715720 📌 标签: [房地产 房地产格局]
|
||||||
|
2026/04/10 16:53:04.715720 📌 ==================================================
|
||||||
|
2026/04/10 16:53:04.715720 📌 初始化浏览器。。。。
|
||||||
|
|
||||||
|
2026/04/10 16:53:05 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
|
||||||
|
[421.319ms] [rows:1]
|
||||||
|
SELECT
|
||||||
|
p.request_id,
|
||||||
|
p.plat_index,
|
||||||
|
p.title,
|
||||||
|
p.tag,
|
||||||
|
p.user_index,
|
||||||
|
p.url,
|
||||||
|
p.img,
|
||||||
|
p.publish_time,
|
||||||
|
p.status,
|
||||||
|
pl.index as plat_index_value,
|
||||||
|
pl.status as plat_status,
|
||||||
|
pl.login_url,
|
||||||
|
pl.edit_url,
|
||||||
|
pl.logined_url,
|
||||||
|
pl.desc
|
||||||
|
FROM publish p
|
||||||
|
INNER JOIN plat pl ON p.plat_index COLLATE utf8mb4_unicode_ci = pl.index AND pl.status = 1
|
||||||
|
WHERE uid='5b37ab96-e0de-46' AND p.token_id = 1
|
||||||
|
ORDER BY p.publish_time DESC
|
||||||
|
LIMIT 1
|
||||||
|
|
||||||
|
publish
|
||||||
|
2026/04/10 16:53:05.009080 ================================================================================
|
||||||
|
2026/04/10 16:53:05.009080 任务开始 | RequestID: 2 | 时间: 2026-04-10 16:53:05.009
|
||||||
|
2026/04/10 16:53:05.009080 ================================================================================
|
||||||
|
2026/04/10 16:53:05.009080 [任务 2] 开始处理(headless=true)
|
||||||
|
2026/04/10 16:53:05.009080 [任务 2] 任务详情 - 平台:xhs,标题:健身与猝死的关系,用户:0d86b848uu2183uu4a08
|
||||||
|
2026/04/10 16:53:05.009080 [任务 2] 标签解析完成: [健身 猝死]
|
||||||
|
2026/04/10 16:53:05.009080 [任务 2] 开始下载文档...
|
||||||
|
2026/04/10 16:53:05 [Worker-1] 开始处理任务 requestID=2
|
||||||
|
2026/04/10 16:53:05.067271 [任务 2] ✅ 文档下载成功: D:\gop\geoGo\docs\2.docx
|
||||||
|
2026/04/10 16:53:05.067271 [任务 2] 开始下载图片...
|
||||||
|
2026/04/10 16:53:05.309691 [任务 2] ✅ 图片下载成功: D:\gop\geoGo\images\2_ec459546-2873-4539-ae96-4d99c19ec62d.jpg
|
||||||
|
2026/04/10 16:53:05.309691 [任务 2] 开始提取文档内容...
|
||||||
|
|
||||||
|
2026/04/10 16:53:05 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
|
||||||
|
[401.004ms] [rows:0]
|
||||||
|
UPDATE publish p
|
||||||
|
SET p.status = 2,uid='d54d1bab-80a4-4a'
|
||||||
|
WHERE p.request_id = (
|
||||||
|
SELECT request_id FROM (
|
||||||
|
SELECT p2.request_id
|
||||||
|
FROM publish p2
|
||||||
|
INNER JOIN plat pl ON p2.plat_index COLLATE utf8mb4_unicode_ci = pl.index
|
||||||
|
WHERE p2.token_id = 1
|
||||||
|
AND p2.status = 1
|
||||||
|
AND p2.publish_time <= '2026-04-10 16:53:04'
|
||||||
|
AND pl.status = 1
|
||||||
|
ORDER BY p2.publish_time ASC
|
||||||
|
LIMIT 1
|
||||||
|
) AS tmp
|
||||||
|
)
|
||||||
|
AND p.status = 1
|
||||||
|
|
||||||
|
publish
|
||||||
|
2026/04/10 16:53:06.894855 [任务 2] ✅ 内容提取成功,长度: 2274
|
||||||
|
2026/04/10 16:53:06.894855 [任务 2] 开始执行发布...
|
||||||
|
2026/04/10 16:53:06.894855 📌 ==================================================
|
||||||
|
2026/04/10 16:53:06.894855 📌 开始执行:xhs
|
||||||
|
2026/04/10 16:53:06.894855 📌 标题: 健身与猝死的关系
|
||||||
|
2026/04/10 16:53:06.894855 📌 标签: [健身 猝死]
|
||||||
|
2026/04/10 16:53:06.894855 📌 ==================================================
|
||||||
|
2026/04/10 16:53:06.894855 📌 初始化浏览器。。。。
|
||||||
|
2026/04/10 16:53:07.849886 ✅ 初始化: 成功
|
||||||
|
2026/04/10 16:53:08.352714 ✅ 保存cookie: 成功
|
||||||
|
2026/04/10 16:53:09.245978 ✅ 初始化: 成功
|
||||||
|
2026/04/10 16:53:09.748755 ✅ 保存cookie: 成功
|
||||||
|
2026/04/10 16:53:10.331882 📌 已点击上传按钮
|
||||||
|
2026/04/10 16:53:11.332203 ✅ 点击上传按钮: 成功
|
||||||
|
2026/04/10 16:53:11.832762 📌 输入文章内容...
|
||||||
|
2026/04/10 16:53:12.378724 📌 清空编辑器失败: eval js error: TypeError: Cannot set properties of undefined (setting 'innerText')
|
||||||
|
at HTMLDivElement.<anonymous> (<anonymous>:1:44)
|
||||||
|
at HTMLDivElement.<anonymous> (<anonymous>:1:127) <nil>
|
||||||
|
2026/04/10 16:53:12.748818 📌 内容已输入,长度: 2274
|
||||||
|
2026/04/10 16:53:12.748818 ✅ 输入内容: 成功
|
||||||
|
2026/04/10 16:53:13.249362 📌 输入标题...
|
||||||
|
|
||||||
|
2026/04/10 16:53:37 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
|
||||||
|
[438.945ms] [rows:0]
|
||||||
|
UPDATE publish p
|
||||||
|
SET p.status = 2,uid='49e9bf0f-120a-4c'
|
||||||
|
WHERE p.request_id = (
|
||||||
|
SELECT request_id FROM (
|
||||||
|
SELECT p2.request_id
|
||||||
|
FROM publish p2
|
||||||
|
INNER JOIN plat pl ON p2.plat_index COLLATE utf8mb4_unicode_ci = pl.index
|
||||||
|
WHERE p2.token_id = 1
|
||||||
|
AND p2.status = 1
|
||||||
|
AND p2.publish_time <= '2026-04-10 16:53:37'
|
||||||
|
AND pl.status = 1
|
||||||
|
ORDER BY p2.publish_time ASC
|
||||||
|
LIMIT 1
|
||||||
|
) AS tmp
|
||||||
|
)
|
||||||
|
AND p.status = 1
|
||||||
|
|
||||||
|
publish
|
||||||
|
2026/04/10 16:54:02 任务执行超时,[Worker-0] context deadline exceeded requestID=1
|
||||||
|
2026/04/10 16:54:02.688485 click fail:context deadline exceeded
|
||||||
|
2026/04/10 16:54:02.688485 ❌ 点击上传按钮: 失败 JS点击按钮失败: context deadline exceeded
|
||||||
|
2026/04/10 16:54:02.689219 [任务 1] ❌ 发布失败: 点击上传按钮失败: JS点击按钮失败: context deadline exceeded
|
||||||
|
|
||||||
|
2026/04/10 16:54:03 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
|
||||||
|
[421.134ms] [rows:1] UPDATE publish SET status = 3, msg = '任务执行超时,[Worker-0] context deadline exceeded requestID=1' WHERE token_id=1 AND request_id = '1'
|
||||||
|
publish
|
||||||
|
|
||||||
|
2026/04/10 16:54:03 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
|
||||||
|
[470.041ms] [rows:1] UPDATE publish SET status = 3, msg = '点击上传按钮失败: JS点击按钮失败: context deadline exceeded' WHERE token_id=1 AND request_id = '1'
|
||||||
|
publish
|
||||||
|
2026/04/10 16:54:03.159260 ================================================================================
|
||||||
|
2026/04/10 16:54:03.159260 任务结束 | RequestID: 1 | 结果: false
|
||||||
|
2026/04/10 16:54:03.159767 [任务 1] 已删除文档文件: D:\gop\geoGo\docs\1.docx
|
||||||
|
2026/04/10 16:54:03.160296 [任务 1] 已删除图片文件: D:\gop\geoGo\images\1_9ffe0dd7-108b-455d-aca4-bf729eba7ab9.png
|
||||||
|
2026/04/10 16:54:05 任务执行超时,[Worker-1] context deadline exceeded requestID=2
|
||||||
|
2026/04/10 16:54:05.009280 ❌ 输入标题: 失败 未找到标题输入框
|
||||||
|
2026/04/10 16:54:05.009280 [任务 2] ❌ 发布失败: 输入标题失败: 未找到标题输入框
|
||||||
|
|
||||||
|
2026/04/10 16:54:05 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
|
||||||
|
[403.700ms] [rows:1] UPDATE publish SET status = 3, msg = '任务执行超时,[Worker-1] context deadline exceeded requestID=2' WHERE token_id=1 AND request_id = '2'
|
||||||
|
publish
|
||||||
|
|
||||||
|
2026/04/10 16:54:05 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
|
||||||
|
[428.723ms] [rows:1] UPDATE publish SET status = 3, msg = '输入标题失败: 未找到标题输入框' WHERE token_id=1 AND request_id = '2'
|
||||||
|
publish
|
||||||
|
2026/04/10 16:54:05.438513 ================================================================================
|
||||||
|
2026/04/10 16:54:05.438513 任务结束 | RequestID: 2 | 结果: false
|
||||||
|
2026/04/10 16:54:05.439077 [任务 2] 已删除文档文件: D:\gop\geoGo\docs\2.docx
|
||||||
|
2026/04/10 16:54:05.439641 [任务 2] 已删除图片文件: D:\gop\geoGo\images\2_ec459546-2873-4539-ae96-4d99c19ec62d.jpg
|
||||||
|
|
||||||
|
|
||||||
16
pkg/func.go
16
pkg/func.go
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/rand/v2"
|
"math/rand/v2"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
@ -315,3 +316,18 @@ func ParseTags(tagStr string) []string {
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetFreePort() (int, error) {
|
||||||
|
addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
l, err := net.ListenTCP("tcp", addr)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
|
||||||
|
return l.Addr().(*net.TCPAddr).Port, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue