Skip to content

Inconsistent timezones in /connz output #6694

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
alexbozhenko opened this issue Mar 19, 2025 · 6 comments
Open

Inconsistent timezones in /connz output #6694

alexbozhenko opened this issue Mar 19, 2025 · 6 comments
Labels
defect Suspected defect such as a bug or regression

Comments

@alexbozhenko
Copy link
Contributor

Observed behavior

nats-server -c noauth.conf
Observe that the time zone of last_activity depends on a number of messages processed:

# curl -s  localhost:8222/connz | jq '.connections | .[]  | {cid,port,start,last_activity,in_msgs}  '
{
  "cid": 7,
  "port": 49728,
  "start": "2025-03-19T15:38:53.554328511-07:00",
  "last_activity": "2025-03-19T15:38:53.555454375-07:00",
  "in_msgs": 1
}
{
  "cid": 8,
  "port": 49734,
  "start": "2025-03-19T15:38:53.555259309-07:00",
  "last_activity": "2025-03-19T22:38:53.555779717Z",
  "in_msgs": 0
}

Client code:

func main() {
	nc, err := nats.Connect(nats.DefaultURL)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer nc.Drain()

	fmt.Println(nc.ConnectedServerVersion())
	nc.Publish("yo", []byte("hello"))
	nc.Subscribe("events", func(m *nats.Msg) {
		fmt.Printf("Received a message: %s\n", string(m.Data))
	})
	nc2, err := nats.Connect(nats.DefaultURL)
	fmt.Println(nc2.ConnectedServerVersion())
	for {

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

The one in UTC has "in_msgs": 0,, so it is likely was handled by this line:

c.last = time.Now().UTC()

It was last changed in #1943

The one with the local timezone has in_msgs != 0, so it is likely was handled by this line:

nats-server/server/client.go

Lines 1256 to 1266 in adb1fcb

last := time.Now()
// Check pending clients for flush.
for cp := range c.pcd {
// TODO(dlc) - Wonder if it makes more sense to create a new map?
delete(c.pcd, cp)
// Queue up a flush for those in the set
cp.mu.Lock()
// Update last activity for message delivery
cp.last = last

It was last changed in #4132

Expected behavior

Consistency.

Server and client version

v2.11.0
nats.go v1.39.0

Host environment

No response

Steps to reproduce

No response

@alexbozhenko alexbozhenko added the defect Suspected defect such as a bug or regression label Mar 19, 2025
@alexbozhenko alexbozhenko changed the title Inconsistent timezones in /varz output Inconsistent timezones in /connz output Mar 19, 2025
@alexbozhenko
Copy link
Contributor Author

alexbozhenko commented Mar 19, 2025

There are other places where time is user-facing, and is not in UTC, e.g.:

nats-server/server/server.go

Lines 3162 to 3170 in 99e836e

now := time.Now()
c := &client{
srv: s,
nc: conn,
opts: defaultOpts,
mpay: maxPay,
msubs: maxSubs,
start: now,

@wallyqs that was reverted from UTC in: #4154

Instead of thinking which one is user-facing time and which one is not, can we simply set the timezone to be UTC in the beginning of the nats server run, and use time.Now() everywhere, without ever thinking about which is local, and which has monotonic clock?

func main() {
	fmt.Println(time.Now())
	fmt.Println(time.Local)

	time.Local = time.UTC

	fmt.Println(time.Local)
	fmt.Println("Still has monotonic clock, but in UTC")
	fmt.Println(time.Now())

	fmt.Println("Does not have monotonic clock")
	fmt.Println(time.Now().UTC())
}
2025-03-19 16:11:39.805474167 -0700 PDT m=+0.000727548
Local
UTC
Still has monotonic clock, but in UTC:
2025-03-19 23:11:39.80555561 +0000 UTC m=+0.000808991

Does not have monotonic clock:
2025-03-19 23:11:39.805562743 +0000 UTC

People do it:
https://github.com/search?q=lang%3Ago+%2Ftime.Local+%3D+time.UTC%2F&type=code
so maybe not the craziest idea?

@derekcollison
Copy link
Member

Might be a good idea..

@ripienaar
Copy link
Contributor

Would certainly simplify things but I worry about doing that

If someone embeds the server we wouldn’t want to mess with the timezone unconditionally. And if we don’t then there are significant behaviour change between embedded or not.

I suspect best we can do is fix the bugs here

@neilalexander
Copy link
Member

I think it's OK if we set time.Local = time.UTC in the main() function in main.go as a catch-all, but I wouldn't do it anywhere else in case of embedding.

@ripienaar
Copy link
Contributor

But then embedded nats will return times different from standalone. This seems like a bad outcome.

@derekcollison
Copy link
Member

I agree might not be good. Would also be nice if a request for info could have a header that asked for the TZ for the results.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
defect Suspected defect such as a bug or regression
Projects
None yet
Development

No branches or pull requests

4 participants