package util import ( "backend/Type" "backend/common" "fmt" "log" "time" ) var loc *time.Location // 时区 func init() { loc, _ = time.LoadLocation("Europe/London") } func ScheduleDailyTask() { //Statistics() for { now := time.Now().In(loc) next := now.AddDate(0, 0, 1).Truncate(24 * time.Hour) duration := next.Sub(now) + 3600*time.Second // 每天凌晨1点执行 time.Sleep(duration) // 执行统计函数 Statistics() } } func Statistics() { log.Println("start statistics") AppConfig, err := GetAppConfig(3) if err != nil { log.Printf("failed to get app config: %v", err) return } LogDb := MPool.GetTopicDB(AppConfig.Topic) defer LogDb.Close() for i := 0; i <= 30; i++ { remain(-i, LogDb, AppConfig) } log.Println("end statistics") SendInfo(LogDb) } func remain(Day int, LogDb *db, AppConfig *Type.AppStruct) { defer func() { if err := recover(); err != nil { log.Printf("remain panic: %v", err) } }() now := ZeroTimestampByTz(AppConfig.Tz) + int64(Day)*86400 Date := time.Unix(now, 0).In(loc).Format("2006-01-02") SecondRemain, _ := DayRemain(now, 1, LogDb) // 计算次留 ThirdRemain, _ := DayRemain(now, 2, LogDb) // 计算三留 SeventhRemain, _ := DayRemain(now, 6, LogDb) // 计算七留 FourteenthRemain, _ := DayRemain(now, 13, LogDb) // 计算14留 ThirtiethRemain, _ := DayRemain(now, 29, LogDb) // 计算30留 Register, _ := DayRemain(now, 0, LogDb) // 计算注册 Login := Login(now, LogDb) // 计算登录 Recharge := Recharge(now, LogDb) // 计算充值 Db := MPool.GetTopicDB(AppConfig.Topic) if Db == nil { log.Printf("failed to get mysql database") return } _, err := Db.Exec("INSERT INTO `remain` (`Date`, `SecondRemain`, `ThirdRemain`, `SeventhRemain`, `FourteenthRemain`, `ThirtiethRemain`, `Register`, `Login`, `Recharge`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE SecondRemain = ?, ThirdRemain = ?, SeventhRemain = ?, FourteenthRemain = ?, ThirtiethRemain = ?, Register = ?, Login = ?, Recharge = ?", Date, SecondRemain, ThirdRemain, SeventhRemain, FourteenthRemain, ThirtiethRemain, Register, Login, Recharge, SecondRemain, ThirdRemain, SeventhRemain, FourteenthRemain, ThirtiethRemain, Register, Login, Recharge) if err != nil { log.Printf("failed to insert data: %v", err) } log.Printf("remain %s success", Date) } func DayRemain(now int64, Day int, LogDb *db) (int, error) { if LogDb == nil { log.Println("failed to get mysql database") return 0, fmt.Errorf("failed to get mysql database") } Timestamp := now + int64(Day)*86400 // log.Print("secondRemain:", Timestamp) type data struct { Uid int `db:"Uid"` } dataList := []data{} err := LogDb.Select(&dataList, "SELECT Uid FROM log_login WHERE Event = 'register' and Timestamp >= ? and Timestamp <= ?", now, now+86399) if err != nil { log.Fatalf("failed to select data: %v", err) } if Day == 0 { return len(dataList), nil } if len(dataList) == 0 { return 0, nil } UidStr := "" for _, v := range dataList { UidStr += fmt.Sprintf("%d,", v.Uid) } if len(UidStr) > 0 { UidStr = UidStr[:len(UidStr)-1] } DataList2 := []data{} Sql := fmt.Sprintf("SELECT `Uid` FROM `log_login` WHERE `Event` = 'Login_log' and `Uid` in ( %s ) and Timestamp >= ? and Timestamp <= ? group by `Uid`", UidStr) err = LogDb.Select(&DataList2, Sql, Timestamp, Timestamp+86399) if err != nil { log.Fatalf("failed to select data: %v", err) } if len(UidStr) < len(DataList2) { log.Printf("UidStr:%d, DataList2:%d", len(UidStr), len(DataList2)) } return len(DataList2), nil } func Login(Now int64, LogDb *db) int { if LogDb == nil { log.Println("failed to get mysql database") return 0 } var Login int err := LogDb.Get(&Login, "SELECT count(distinct Uid) as count FROM log_login WHERE Event = 'Login_log' and Timestamp >= ? and Timestamp <= ?", Now, Now+86399) if err != nil { log.Fatalf("failed to get login data: %v", err) } return Login } func Recharge(Now int64, LogDb *db) float64 { if LogDb == nil { log.Println("failed to get mysql database") return 0 } var Recharge float64 err := LogDb.Get(&Recharge, "SELECT IFNULL(Sum(Price),0.0) as sum FROM log_order WHERE Timestamp >= ? and Timestamp <= ?", Now, Now+86399) if err != nil { log.Fatalf("failed to get recharge data: %v", err) } return Recharge } func SendInfo(Db *db) error { if Db == nil { log.Printf("GetOperation MySQL nil") return nil } defer Db.Close() Retain := []*Type.Retain{} ZeroTimestamp := ZeroTimestampByTz("Europe/London") - 86400 ZeroTime := time.Unix(ZeroTimestamp, 0).In(time.UTC) StartDate := ZeroTime.AddDate(0, 0, -7).Format("2006-01-02") EndDate := ZeroTime.Format("2006-01-02") err := Db.Select(&Retain, "SELECT `Date`, `Register`, `SecondRemain`, `ThirdRemain`, `SeventhRemain`, `ThirtiethRemain`, `Recharge`, `Login` FROM remain where `Date` >= ? and `Date` <= ? order by `Date` desc", StartDate, EndDate) if err != nil { log.Printf("GetOperation Select error: %v", err) return err } var Register int err = Db.Get(&Register, "SELECT count(`Uid`) as count FROM log_login WHERE Event = 'register'") if err != nil { log.Printf("GetOperation Select error: %v", err) return err } var Recharge float64 err = Db.Get(&Recharge, "SELECT IFNULL(SUM(Price), 0) as sum FROM log_order") if err != nil { log.Printf("GetOperation Select error: %v", err) return err } var InactiveUsers int err = Db.Get(&InactiveUsers, "SELECT count(distinct Uid) as count from (SELECT Uid, MAX(Timestamp) as LastLogin FROM log_login WHERE Event = 'Login_log' GROUP BY Uid) as lt where lastlogin < ?", ZeroTimestamp-7*86400) if err != nil { log.Printf("GetOperation Select error: %v", err) return err } ChurnRate := 100 * float64(InactiveUsers) / float64(Register) Result := &Type.Operation{Retain: Retain, Register: Register, Recharge: Recharge, ChurnRate: ChurnRate} err = common.SendOperationMsg(Result) if err != nil { log.Printf("SendOperationMsg error: %v", err) return err } return nil }