Skip to content
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

feat: Serialize duration as string, not as nanosecs, in API responses and DB #1542

Merged
merged 4 commits into from
Jan 26, 2024

Conversation

michaljurecko
Copy link
Contributor

@michaljurecko michaljurecko commented Jan 25, 2024

Part of: https://keboola.atlassian.net/browse/PSGO-388

Changes:

  • time.Duration is by default serialized as int64, as number of nanoseconds.
  • It is acceptable for database, but it complicates E2E tests.
  • It is not acceptable for API, we had some conversions implemented on the API layer.
  • Now, we have in the API much more time.Duration values that need to be handled.
  • So I created duration.Duration type, that serializes as string, for example: 100ms, 1h0m, ...
  • It is not implemented in the Go in this ways, to keep BC:
  • We have similar package for the time serialization, see utctime pkg.

@michaljurecko michaljurecko force-pushed the michaljurecko-PSGO-387-duration-pkg branch from b8e7465 to daccaa0 Compare January 25, 2024 18:04
Comment on lines +1 to +7
// Package duration provides a wrapper for time.Duration type,
// to serialize duration as string instead of int64 nanoseconds.
//
// This cannot be changed in Go 1.X, it would break backward compatibility, see:
// https://github.com/golang/go/issues/10275
// "This isn't possible to change now, as it would change the encodings produced by programs that exist today."
package duration
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docs.

Comment on lines 472 to 478
"wait": false,
"checkInterval": 1000000,
"checkInterval": "1ms",
"countTrigger": 100,
"bytesTrigger": "100KB",
"intervalTrigger": 100000000
"intervalTrigger": "100ms"
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change in the database snapshot.

Comment on lines 39 to 41
syncCounter++
clk.Add(cfg.SyncInterval)
clk.Add(cfg.SyncInterval.Duration())
assert.Eventually(t, func() bool {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in related code.

@michaljurecko michaljurecko marked this pull request as ready for review January 25, 2024 18:07
Copy link
Contributor

@hosekpeter hosekpeter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Comment on lines +144 to +147
if v, ok := fl.Field().Interface().(time.Duration); ok {
value = v
} else if v, ok := fl.Field().Interface().(duration.Duration); ok {
value = v.Duration()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay I think I need a bit more info on type casting here. 🤔 With duration.Duration being defined as

type Duration time.Duration

I'd expect the first condition to pass even for duration.Duration so the second branch would never happen.

If that's not the case, what am I missing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notes from call:

var value any = duration.Duration(123) // 123ns
var value any = int64(123)

--------------

if v, ok := value.(duration.Duration); ok {
  // ...
}

--------------

swtich v := value.(type) {
  case duration.Duration:
  case int64:
  default:
    panic(....)
}

Comment on lines -19 to +22
SyncInterval time.Duration `configKey:"interval" configUsage:"Statistics synchronization interval, from memory to the etcd." validate:"required,minDuration=100ms,maxDuration=5s"`
SyncTimeout time.Duration `configKey:"timeout" configUsage:"Statistics synchronization timeout." validate:"required,minDuration=1s,maxDuration=1m"`
SyncInterval duration.Duration `configKey:"interval" configUsage:"Statistics synchronization interval, from memory to the etcd." validate:"required,minDuration=100ms,maxDuration=5s"`
SyncTimeout duration.Duration `configKey:"timeout" configUsage:"Statistics synchronization timeout." validate:"required,minDuration=1s,maxDuration=1m"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder, should we disallow time.Duration in linter?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, if the struct is not used in db/api, time.Duration is ok.

Base automatically changed from michaljurecko-PSGO-387-config-patch to RFC-2023-008 January 26, 2024 11:19
@michaljurecko michaljurecko merged commit da4629e into RFC-2023-008 Jan 26, 2024
6 checks passed
@michaljurecko michaljurecko deleted the michaljurecko-PSGO-387-duration-pkg branch January 26, 2024 11:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants