I need to monitor the status of the N sensors and log it. I am creating a 
separate goroutine for each sensor which fetches the state and logs it at 
regular intervals. For each goroutine, a channel is created to read the 
termination signal. Each sensor's state is maintained in sync.Map. The map 
maintains a pointer to the state. Apart from monitoring goroutines, there 
are processing goroutines that update the sensor's state.

In my current implementation, the goroutines are able to log the status at 
regular intervals. But after a few days, some goroutines stop logging the 
status. But the processing goroutines are able to update the status. 

As a goroutine may terminate if panic occurs, I used recover() to log the 
error and the monitoring thread is re-created. But this doesn't help 
either. I noticed that the goroutine has been terminated but error hasn't 
been logged.

I suspect that because of memory leak, the goroutine might be terminated.

Please find attached sample code.


It will be helpful if someone explains this abnormal behavior and provides 
possible solutions.
Thanks

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/0936fbc8-9f47-45ca-9e93-a6f6590f3adcn%40googlegroups.com.
// sensor state struct
type sensorState struct {
    a float64
    b int
    lock sync.Mutex
    ch   chan int
}

type curStatus struct {
    a float64
    b int
    ...
}

// log struct
type stateLog struct {
    state curStatus
    timestamp int64
    method string
}

// stateMap maintains state of different sensors
var stateMap sync.Map
stateMap.Store("Sensor-A", &sensorState{
                      a : 0,
                      b : 0,
                      lock : sync.Mutex{},
                      ch : make(chan int)
               })


func ChargerMonitoringThreadV2(sensorId string) {

    isStateLocked := false
    sensorStatus := curStatus{}

    sessionState, _ := stateMap.Load(sensorId)
    state, _ := sessionState.(*sensorState)

    defer func() {
        if er := recover(); er != nil {
            fmt.Printf("ERROR: [sensorId:%s][ChargerMonitoringThreadV2] 
Recovered from - %v", sensorId, er)
            fmt.Printf("ERROR: [sensorId:%s][ChargerMonitoringThreadV2] 
stacktrace from panic:\n%s", sensorId, string(debug.Stack()))

            if isStateLocked {
                fmt.Printf("INFO: [sensorId:%s][ChargerMonitoringThreadV2] 
Released  lock\n", sensorId)
                state.lock.Unlock()
                isStateLocked = false
            }

            go ChargerMonitoringThreadV2(sensorId)
            logging.ReportException(fmt.Errorf("%v\n%s", er, 
string(debug.Stack()))) // log error
            return
        }
    }()

    for {
        select {
       
        case <-state.ch:
            fmt.Printf("INFO: [sensorId:%s][monitoringThread] Terminating 
monitoring thread...\n", sensorId)
            return
           
        default:

            curTS := time.Now().UnixMilli()

            state.lock.Lock()
            isSessionStateLocked = true

            sensorStatus.a = state.a

            state.lock.Unlock()
            isSessionStateLocked = false

            insertLog(&stateLog{
                state:     sensorStatus,
                timestamp: curTS,
                method:    "monitoringThread",
            })

            time.Sleep(60 * time.Second)
        }
    }
}

Reply via email to