getwtxt/getwtxt

View on GitHub
svc/periodic.go

Summary

Maintainability
A
0 mins
Test Coverage
/*
Copyright (c) 2019 Ben Morrison (gbmor)

This file is part of Getwtxt.

Getwtxt is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Getwtxt is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Getwtxt.  If not, see <https://www.gnu.org/licenses/>.
*/

package svc // import "git.sr.ht/~gbmor/getwtxt/svc"

import (
    "log"
    "time"

    "github.com/fsnotify/fsnotify"
)

// Functions and types in this file pertain
// to periodic, regular actions.

// This is a wrapper for a *time.Ticker
// that adds another channel. It's used
// to signal to the ticker goroutines
// that they should stop the tickers
// and exit.
type tick struct {
    isDB bool
    t    *time.Ticker
    exit chan struct{}
}

// Creates a new instance of a tick
func initTicker(db bool, interval time.Duration) *tick {
    return &tick{
        isDB: db,
        t:    time.NewTicker(interval),
        exit: make(chan struct{}, 1),
    }
}

// Sends the signal to stop the tickers
// and for their respective goroutines
// to exit.
func killTickers() {
    ct := <-cTickC
    dt := <-dbTickC
    ct.exit <- struct{}{}
    dt.exit <- struct{}{}
}

// Waits for a signal from the database
// *tick. Either stops the ticker and
// kills the goroutine or it will
// update cache / push the DB to disk
func dataTimer(tkr *tick) {
    for {
        select {
        case signal := <-tkr.t.C:
            if tkr.isDB {
                errLog("", pushDB())
                log.Printf("Database push took: %v\n", time.Since(signal))
                continue
            }
            cacheUpdate()
            log.Printf("Cache update took: %v\n", time.Since(signal))
        case <-tkr.exit:
            tkr.t.Stop()
            return
        }
    }
}

// Called when a change is detected in the
// configuration file. Closes log file,
// closes database connection, stops all
// tickers, then binds new configuration
// values, opens new log file, connects to
// new database, and starts new cache and
// database tickers.
func reInit(e fsnotify.Event) {
    log.Printf("%v. Reloading...\n", e.String())

    if !confObj.StdoutLogging {
        closeLog <- struct{}{}
    }

    killTickers()
    bindConfig()
    initLogging()
    initPersistence()
}

// Starts the tickers that periodically:
//  - pull new user statuses into cache
//  - push cached data to disk
func initPersistence() {
    confObj.Mu.RLock()
    cacheTkr := initTicker(false, confObj.CacheInterval)
    dbTkr := initTicker(true, confObj.DBInterval)
    confObj.Mu.RUnlock()

    go dataTimer(cacheTkr)
    go dataTimer(dbTkr)

    dbTickC <- dbTkr
    cTickC <- cacheTkr
}