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

2 - Broadcast - Datatypes #199

Open
wants to merge 1 commit into
base: features/broadcast/logging
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions broadcast/dtos/dtos.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package dtos
Copy link
Member

Choose a reason for hiding this comment

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

We need a package doc comment for dtos to explain what it is and provides.

Copy link
Member

Choose a reason for hiding this comment

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

Maybe the package name could be more specific. I can't figure out what it means, so I can't think of something better.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It's supposed to contain all dto's that are referenced outside of the broadcast package context (including subfolders). The main idea is to prevent cyclic imports and provide a common namespace for dto's pertaining to broadcast outside of the broadcast context. I.e. instead of referencing processor.RequestDto and router.Msg in gorums/server.go, I thought it would be easier to use dtos.RequestDto and dtos.Msg. Hoping this would reduce the cognitive load of developers working with higher level functionality such as nodes/channels, as both processor and router are implementation details specific to broadcasting.

Naming things are not my strong suit, so feel free to rename/change. If you think it is better, the dtos could also be moved to their respective packages (RequestDto -> processor, the rest -> router).


import (
"context"
"google.golang.org/protobuf/reflect/protoreflect"
"time"
)

type Msg interface {
GetBroadcastID() uint64
GetMethod() string
String() string
}

type BroadcastMsg struct {
Copy link
Member

Choose a reason for hiding this comment

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

It would be quite useful with doc comments for structs, methods, fields etc. Especially, those fields that aren't common knowledge, such as Info, Options, OriginAddr.

Ctx context.Context
Copy link
Member

Choose a reason for hiding this comment

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

Difficult to assess, since I don't know the use of the Ctx field here, but it is a antipattern to include context.Context in structs. See the Context and Structs blog post. It should be passed as the first argument to all functions/methods that need a context. But see the blog for concrete advice.

Options BroadcastOptions
OriginAddr string
Info Info
}

func (msg *BroadcastMsg) GetBroadcastID() uint64 {
return msg.Info.BroadcastID
}

func (msg *BroadcastMsg) GetMethod() string {
return msg.Info.Method
}

func (msg *BroadcastMsg) String() string {
return "broadcast"
}

type ReplyMsg struct {
Info Info
ClientAddr string
Err error
}

func (r *ReplyMsg) GetBroadcastID() uint64 {
return r.Info.BroadcastID
}

func (r *ReplyMsg) GetMethod() string {
return "reply"
}

func (r *ReplyMsg) String() string {
return "reply"
}

type Info struct {
Message protoreflect.ProtoMessage
BroadcastID uint64
Method string
Addr string
OriginMethod string
OriginDigest []byte
OriginSignature []byte
OriginPubKey string
}

type Client struct {
Addr string
SendMsg func(timeout time.Duration, dto *ReplyMsg) error
Close func() error
}

type BroadcastOptions struct {
Copy link
Member

Choose a reason for hiding this comment

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

This question applies to the all types and fields in the PR: Is it intentional that all types and fields are exported? Are they needed outside the broadcast/dtos package?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, they are. I provided a longer explanation to one of the comments above. 👍

ServerAddresses []string
AllowDuplication bool
SkipSelf bool
ProgressTo string
RelatedToReq uint64
}
57 changes: 57 additions & 0 deletions broadcast/errors/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package broadcastErrors
Copy link
Member

Choose a reason for hiding this comment

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

Go packages shouldn't use camel case. However, it is also uncommon to have errors in a separate package. Since I assume your errors are specific to broadcast, they should probably be part of the broadcast package.

Some notable exceptions exist, e.g., upspin. Since Upspin is a large project, they standardize on a particular error style across the whole project. We could do the same, but perhaps that would be part of Asbjørn's thesis work.

Copy link
Member

Choose a reason for hiding this comment

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

Note also: Since the package is declared as broadcastErrors but the file is saved in the errors folder, this will not compile.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

My bad. The package should've been renamed to errors. I agree that they should not be in their own package. I'm just not very happy with how the logging wrapper currently operates, as it pollutes the code a bit (see the log statements in processor.go). I was hoping to improve this my including more context/fields in each error and log the errors directly. Hopefully making the logging a bit less verbose and at the same time making the errors a bit more explicit.

Since this is not implemented yet, it is probably better to move the errors to the packages that references them.


type BroadcastIDErr struct{}
Copy link
Member

Choose a reason for hiding this comment

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

Rename it to IDErr to avoid stuttering.

Usage from outside the broadcast package would be broadcast.IDErr instead of broadcast.BroadcastIDErr.


func (err BroadcastIDErr) Error() string {
return "wrong broadcastID"
Copy link
Member

Choose a reason for hiding this comment

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

General comment for all error strings. It can be easier to interpret errors if they are prefixed by the package name, e.g.,:

return "broadcast: wrong broadcastID"
// OR unless there are many types IDs, maybe it would suffice:
return "broadcast: wrong ID"

}

type MissingClientReqErr struct{}
Copy link
Member

Choose a reason for hiding this comment

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

Would be nice to have doc comments on these errors too.


func (err MissingClientReqErr) Error() string {
return "has not received client req yet"
Copy link
Member

Choose a reason for hiding this comment

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

return "client request not received (yet)"

}

type AlreadyProcessedErr struct{}

func (err AlreadyProcessedErr) Error() string {
return "already processed request"
Copy link
Member

Choose a reason for hiding this comment

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

return "request already processed"

Should this be prefixed by client?

}

type ReqFinishedErr struct{}

func (err ReqFinishedErr) Error() string {
return "request has terminated"
Copy link
Member

Choose a reason for hiding this comment

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

return "request terminated"

Should it be prefixed by client?

}

type ClientReqAlreadyReceivedErr struct{}

func (err ClientReqAlreadyReceivedErr) Error() string {
return "the client req has already been received. The forward req is thus dropped."
Copy link
Member

Choose a reason for hiding this comment

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

What about this:

// The forwarded request is dropped since:
return "client request already received"
// OR:
return "client request already received (dropped)"
// OR:
return "forwarded client request already received (dropped)"

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I like number 2 the best. 👍

}

type MissingReqErr struct{}

func (err MissingReqErr) Error() string {
return "a request has not been created yet."
Copy link
Member

Choose a reason for hiding this comment

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

Not sure I understand when this could happen, but here is a shorter error message:

// Add comment here with more context
return "request not created yet"

Don't use . in error messages, since they often get chained:

failed to update user: malformed request

}

type OutOfOrderErr struct{}

func (err OutOfOrderErr) Error() string {
return "the message is out of order"
Copy link
Member

Choose a reason for hiding this comment

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

return "request received out of order"

Is this referring to a client request?

}

type ShardDownErr struct{}

func (err ShardDownErr) Error() string {
return "the shard is down"
Copy link
Member

Choose a reason for hiding this comment

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

// more context?
return "shard is down"

}

type InvalidAddrErr struct {
Addr string
}

func (err InvalidAddrErr) Error() string {
return "provided Addr is invalid. got: " + err.Addr
Copy link
Member

Choose a reason for hiding this comment

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

return fmt.Sprintf("invalid address: %s", err.Addr)

}
2 changes: 1 addition & 1 deletion examples/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ require (
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/relab/gorums v0.7.0
golang.org/x/term v0.18.0
google.golang.org/grpc v1.62.1
google.golang.org/grpc v1.63.0
google.golang.org/protobuf v1.33.0
)

Expand Down
1 change: 1 addition & 0 deletions examples/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk=
google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
google.golang.org/grpc v1.63.0/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 h1:rNBFJjBCOgVr9pWD7rs/knKL4FRTKgpZmsRfV214zcA=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0/go.mod h1:Dk1tviKTvMCz5tvh7t+fh94dhmQVHuCt2OzJB3CTW9Y=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
Expand Down
Loading