-
Notifications
You must be signed in to change notification settings - Fork 220
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
Replace gogo protobuf #1256
Replace gogo protobuf #1256
Conversation
) | ||
|
||
// SerializeBatchEvents serializes batch events into a datablob proto | ||
func SerializeBatchEvents(events []*historypb.HistoryEvent, encodingType enumspb.EncodingType) (*commonpb.DataBlob, error) { | ||
return serialize(&historypb.History{Events: events}, encodingType) | ||
} | ||
|
||
func serializeProto(p proto.Marshaler, encodingType enumspb.EncodingType) (*commonpb.DataBlob, error) { | ||
func serializeProto(p Marshaler, encodingType enumspb.EncodingType) (*commonpb.DataBlob, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would also accept proto.Message
here too (since this is private and it's only on our protos), but what you have here is fine too
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we accept things with a Marshal method then I can sneak vtprotobuf under the hood by swapping out the implementation of Marshal. That way nothing else needs to care about what we're using
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is only for this one part, it's not like you'll "sneak" it in everywhere. Are there plans to discourage the use of proto.Marshal
for this one reason?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll find out: once we have the server working we'll run E2E load and see if there's a measurable performance difference. If "No" (our assumption) then no and I'll skip including vtproto
) | ||
|
||
var ErrProtoNameNotFound = errors.New("protocol name not found") | ||
|
||
// NameFromMessage extracts the name of the protocol to which the supplied | ||
// message belongs. | ||
func NameFromMessage(msg *protocolpb.Message) (string, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we changing the behavior here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A quick and uninformed decision while first learning the proto library. Looks like the anypb.Any type provides MessageName() which would let us have the same behavior
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also if anypb.Body.MessageName() doesn't return a message name then we've no name to report.
The old types package doesn't work with google protobuf; if we want the same semantics I'd probably have to allocate and do something like
_, err := msg.Body.UnmarshalNew()
if err != nil {
return "", fmt.Errorf("unrecognized message type %q: %w", msg.Body.MessageName(), err)
}
e1d8372
to
d234e15
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall looks good, just very minor comments before I hit approve
@@ -77,3 +77,5 @@ jobs: | |||
go-repo-path: ${{github.event.pull_request.head.repo.full_name}} | |||
version: ${{github.event.pull_request.head.ref}} | |||
version-is-repo-ref: true | |||
features-repo-path: "tdeebswihart/temporal-features" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Goes without saying, just making reminder to update this and similar places when temporalio/api-go#119 is merged
@@ -45,7 +48,7 @@ func anyToString(d interface{}) string { | |||
buf.WriteString("(") | |||
for i := 0; i < v.NumField(); i++ { | |||
f := v.Field(i) | |||
if f.Kind() == reflect.Invalid { | |||
if f.Kind() == reflect.Invalid || privateField.MatchString(t.Field(i).Name) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A bit overkill to use regex just to check if the first character of a string is lowercase, but meh
@@ -28,6 +28,9 @@ import ( | |||
"fmt" | |||
"time" | |||
|
|||
"google.golang.org/protobuf/types/known/durationpb" | |||
"google.golang.org/protobuf/types/known/timestamppb" | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit - while some of the older SDK and server code required developers to manually break up non-stdlib sections by same module and separate module, modern SDK rules do not (but harmless for the most part).
) | ||
|
||
var ErrProtoNameNotFound = errors.New("protocol name not found") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Meh, we often don't make exported vars for singly used never otherwise-referenced errors, but no big deal
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a fan of them as you can use them with errors.Is
, and I prefer that to string matching.
I'm happy to yield to our conventions however
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't really have a convention here, so it's fine. I'm a fan of them when I need to use them with errors.Is
, but not for every error in the SDK just because some future user may need to use them with errors.Is
. Hence the "never otherwise-referenced". By that logic, we'd never have anymore inline errors and we'd have a huge API surface which I think is a bit too hardcore of a stance to take here (though may have value for other projects).
(again, no need to change)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've been burnt by Go' stdlib refusing to expose internal networking errors before and have made a habit of it, heh. I'll keep that in mind for future errors I add however
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approving, but please do not merge until dependencies are merged/tagged
This does not yet compile as I removed the proxy. I also still need to implement history cleaning; SDKs should still load old histories that have CamelCase enums
We've swapped the roles of GoV2 and gogo here, so we forcibly include a gogo-generated message definition.
We'll want that functionality in the CLI as well so everything has been moved to a common repo.
I need to see whether the changes will impact our metrics; it's possible given what I found in the grpc_dialer tests
We'll want these in other repos as well so I've moved and renamed them. duration.Proto is clearer than common.DurationPtr and flows better. Refactoring automated using [gopatch](): ```diff @@ @@ +import "go.temporal.io/api/types/duration" -common.DurationValue(...) +duration.Value(...) @@ @@ +import "go.temporal.io/api/types/duration" -common.DurationPtr(...) +duration.Proto(...) @@ @@ +import "go.temporal.io/api/types/duration" -common.MinDurationPtr(...) +duration.MinProto(...) @@ @@ +import "go.temporal.io/api/types/timestamp" -common.TimeValue(...) +timestamp.Value(...) @@ @@ +import "go.temporal.io/api/types/timestamp" -common.TimePtr(...) +timestamp.Proto(...) ```
This way CI can run and others can function
jsonpb is dead, long live jsonpb!
Our error messages and metric tags are back to their old values, so our users shouldn't notice that we changed our proto library.
Let's see if this works
We don't need to specify `resp` twice...
77a077b
to
39f695a
Compare
39f695a
to
49eced6
Compare
I'll remove the usage of my fork of features for CI in a second pass
**What changed?** gogo/protobuf has been replaced with Google's official go compiler. **Why?** gogo/protobuf has been deprecated for some time and the community is moving on, building new tools (like vtproto) atop google's v2 compiler. **How did you test it?** This branch is actively used by my [SDK](temporalio/sdk-go#1256) and [server](temporalio/temporal#5032) PRs so you can see it in use there **Potential risks** None I can think of. **Breaking changes for developers** - `*time.Time` in proto structs will now be [timestamppb.Timestamp](https://pkg.go.dev/google.golang.org/protobuf@v1.31.0/types/known/timestamppb#section-documentation) - `*time.Duration` will now be [durationpb.Duration](https://pkg.go.dev/google.golang.org/protobuf/types/known/durationpb) - V2-generated structs embed locks, so you cannot dereference them. `go vet` will scream at you about this. If you need a copy, use `proto.Clone`. - Proto objects, or objects embedding protos, cannot be compared using `reflect.DeepEqual` or _anything_ that uses it. This includes `testify` and `mock` equality testers! - You will need to use the `protorequire` ro `protoassert`packages instead. I've implemented proto-compatible assertions there for all cases I've encountered - If you need `reflect.DeepEqual` for any reason you can use `go.temporal.io/api/temporalproto.DeepEqual` instead
What was changed?
gogo/protobuf has been replaced with Google's official go compiler.
Why?
gogo/protobuf has been deprecated for some time and the community is moving on, building new tools (like vtproto) atop google's v2 compiler.
Breaking changes
*time.Time
in proto structs will now be timestamppb.Timestamp*time.Duration
will now be durationpb.Durationgo vet
will scream at you about thisSCREAMING_SNAKE_CASE
rather thanPascalCase
. We decided (in discussion with the SDK team) that now was as good a time as any to rip the bandage off.Note that history loading will not be impacted by the JSON changes: I rewrote history loading to dynamically fix incoming history JSON data (like all our other sdks); you can find this code in my fork of our go API alongside its tests.
How did you test it?
All tests for this repo pass as do all SDK tests (except for integration tests, which time out on our official repo on master...).
Potential risks
All errors that could arise from this change should be compile-time errors, so your build will be broken if I haven't yet addressed your code. I plan to port all relevant temporal repos as a part of this effort.
Checklist
Release Plan
Our goal is to release our API, Go API, Go SDK, and Server all at once, then update our UI (and ui-server), CLI, and HTTP API in a second pass. Until the second pass happens no changes to our JSON formatting will be apparent to users