#Timer returns large values for go routines

21 messages · Page 1 of 1 (latest)

idle sentinel
#

Hi Folks!

I am facing a problem in one of my projects. I have created a small service whose job is to calculate the total time taken based on the data pushed into RabbitMQ. The structure of the message is quite simple {JobId uint, Status bool} . I want to calculate and save the total time taken to process a specific Job. For this, I'm pushing 2 instances of the given struct into the queue with Status being **true **when the process is **initiated **and **false **when completed.

Following is the current logic:

func Listener() {
    conn, err := amqp.Dial(os.Getenv("RABBITMQ"))
    logError(err, "Failed to connect to RabbitMQ")
    defer conn.Close()

    ch, err := conn.Channel()
    logError(err, "Failed to open a channel")
    defer ch.Close()

    msgs := createChannel(ch)

    go func() {
        for d := range msgs {
            var data StatusQueue
            err := json.Unmarshal(d.Body, &data)
            logError(err, "failed to unmarshal queue data")
            
            var timer time.Time
            if data.Status {
                timer = time.Now() // Setting the initial value
            } else {
                totalTime := time.Since(timer)

                content := fmt.Sprintf("Total time taken for jobId: %d : %f", data.JobId, totalTime.Seconds())
                log.Println(content)
            }
        }
    }()

    log.Printf(" [*] Waiting for messages. To exit press CTRL+C")
    select {}
}```



Following is the output for the above:
"Total time taken for jobId: 1 : `9223372036.854776`"

The expected output should not be more than a few seconds. I am assuming this has something to do with concurrency. I'm only familiar with waitGroups and Mutexs till now. Thank you for your time.
civic timber
#

time.Since returns a time.Duration which is measured in nanoseconds

red tapirBOT
#
type Duration int64```
A Duration represents the elapsed time between two instants as an int64 nanosecond count. The representation limits the largest representable duration to approximately 290 years.
civic timber
#

oh I misread the code, apologies

#

I see you are calling Seconds

#

the issue is not related to concurrency, it's that you are calling time.Since on a zero value time.Time

idle sentinel
#

Oh, okay. But why does it behave that way? Considering I have initialized the timer in the if construct.

civic timber
#

the key question is which timer you have initialized

#

it's just a local variable scoped to the loop
your code is equivalent to go func f() { var a int if cond { a = 1 } else { // ... } }
in the else branch a is cannot be anything other than 0

idle sentinel
#

Okay, I somewhat understand. But is there a way to workaround this?

#

I got it. It 's a very silly mistake.

civic timber
#

if you want to record when a job was started, that information needs to be attached, either implicitly or otherwise, with the job
if jobs only live in memory, you can just add a startedAt time.Time field

if you are doing more roundtrips through the queue (such as retrying) then you can persist that in the message itself

idle sentinel
#

Sorry, I didn't get you. Can you elaborate on how can I persist the timer for a particular routine? I can only initialize the value in when the status is true and want to use the same when it becomes false.

civic timber
#

who sets the status to true also sets startedAt

#

who sets it to false can do time.Since(msg.startedAt)

idle sentinel
#

Ah okay, that's a good option. Although, will it be possible to achieve the same using just the listener?

#

Is there a way I can keep track of when a specific jobId sends the initial and final notification?

civic timber
#

the fundamental issue is that you need a time.Time per job, anything that accomplishes that is sufficient

#

I don't know why it would be preferable, but even a map[id]time.Time would be enough

idle sentinel
#

Great! Thanks for the help. I know the former solution is the better one. Just wanted to know my options for the sake of it.

#

Should I "Close Post"?