Search code examples
gonats.io

How to create .csv every day


In my application, I listen to nats and the output I get is a map with data. I need to generate a daily csv file using the data from the map. Now the data from the map is written to the file continuously. How can I write data to the file only at the end of each day?

type Hits struct {
    HitMap      map[string]map[SearchRequestKey]uint32 
    Mu          sync.RWMutex
    Log         zerolog.Logger
    TimeStart   time.Time
    MinHits     int
    WasDelete   map[string]int64
    Cnt1        float32
    Version     int
    QQMap       map[string]struct{}
    GitlabToken string
}

type SearchRequestKey struct {
    Query string
    Date  string
}

func FileAdd(hits *models.Hits) {
    file, err := os.OpenFile("query-hits.csv", os.O_CREATE|os.O_RDWR, 0644)
    if err != nil {
        fmt.Println(err)
    }

    writer := csv.NewWriter(file)
    writer.Comma = '|'

    for key, value := range hits.HitMap {
        for query, shard := range value {
            err := writer.Write([]string{query.Query, key, strconv.Itoa(int(shard))})
            if err != nil {
                fmt.Println(err)
            }
        }
    }
}

Solution

  • In order to create a .csv file daily, you need to run the code in a loop and make the current time as the starting point. After 24 hours the function will generate the file again. Finally the way with time.AfterFunc() helped. Don't forget to use mutex.

    type Hits struct {
        HitMap      map[string]map[SearchRequestKey]uint32 
        Mu          sync.RWMutex
        Log         zerolog.Logger
        TimeStart   time.Time
        MinHits     int
        WasDelete   map[string]int64
        Cnt1        float32
        Version     int
        QQMap       map[string]struct{}
        GitlabToken string
    }
    
    type SearchRequestKey struct {
        Query string
        Date  string
    }
    
    func FileAdd(hits *models.Hits) {
        hits.Mu.Lock()
        defer hits.Mu.Unlock()
    
        for {
            year, month, day := time.Now().Date()
            file := strconv.Itoa(year) + month.String() + strconv.Itoa(day)
    
            fileName, err := os.Create(file)
            if err != nil {
                fmt.Println(err)
            }
    
            writer := csv.NewWriter(fileName)
            writer.Comma = '|'
    
            for key, value := range hits.HitMap {
                for query, shard := range value {
                    err := writer.Write([]string{query.Query, key, strconv.Itoa(int(shard))})
                    if err != nil {
                        fmt.Println(err)
                    }
                }
            }
            time.Sleep(24 * time.Hour) //only after 24 hours
        }
    
    }
    
    func FuncThatStart (hits *models.Hits) {
        hits.Mu.Lock()
        defer hits.Mu.Unlock()
    
        // generate for one day
        today := time.Now()
        tomorrow := today.Add(24 * time.Hour) // same time as in time.Sleep()
    
        time.AfterFunc(time.Until(tomorrow), func() {
            go storage.FileAdd(hits) //goroutine handle one time per day
        })
    }
    

    Thanks for comments