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

Last pre-OSS changes #54

Merged
merged 5 commits into from
Oct 13, 2023
Merged
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
16 changes: 16 additions & 0 deletions .github/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
changelog:
Copy link
Member

Choose a reason for hiding this comment

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

Does this belong in our oss skeleton? Does this mean we also need to setup standard labels in every oss repo and to also label every PR to get the items correctly categorized into sections?

Copy link
Member Author

Choose a reason for hiding this comment

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

Sure, I'll put it into the skeleton! I'm not sure how to automate the label creation though. We don't need to label all the PRs - normally, I clean up the release notes and sort things by hand.

exclude:
labels:
- ignore-for-release
authors:
- dependabot
categories:
- title: Enhancements
labels:
- enhancement
- title: Bugfixes
labels:
- bug
- title: Other changes
labels:
- "*"
18 changes: 7 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Go HTTP Client-Side Load Balancing
# httplb

[![Build](https://github.com/bufbuild/httplb/actions/workflows/ci.yaml/badge.svg?branch=main)](https://github.com/bufbuild/httplb/actions/workflows/ci.yaml)
[![Report Card](https://goreportcard.com/badge/github.com/bufbuild/httplb)](https://goreportcard.com/report/github.com/bufbuild/httplb)
Expand Down Expand Up @@ -33,17 +33,13 @@ import (
"time"

"github.com/bufbuild/httplb"
"github.com/bufbuild/httplb/resolver"
"github.com/bufbuild/httplb/picker"
)

func main() {
client := httplb.NewClient(
httplb.WithResolver(
// Use a resolver for IPv4. You can pass "ip" for dual-stack setups,
// or "ip6" for pure IPv6. This defaults to "ip" and assumes IPv6
// is suitable for your deployment.
resolver.NewDNSResolver(net.DefaultResolver, "ip4", 5*time.Minute),
),
Copy link
Member Author

Choose a reason for hiding this comment

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

I changed the example here to be a little shorter and more self-explanatory. WDYT?

Copy link
Member

Choose a reason for hiding this comment

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

I kind of liked showing the resolver option, though perhaps the associated comment is unclear why it's useful to show. I suspect the resolver is the most likely thing people would need to tweak, but I could be wrong 🤷. Anyhow, new example is fine, too.

// Switch from the default round-robin policy to power-of-two.
httplb.WithPicker(picker.NewPowerOfTwo),
)
defer client.Close()
resp, err := client.Get("https://example.com")
Expand All @@ -55,7 +51,8 @@ func main() {
}
```

And here is how you can use `httplb` with `connect-go`:
If you're using [Connect](https://github.com/connectrpc/connect-go), you can
use `httplb` for your RPC clients:

```go
func main() {
Expand Down Expand Up @@ -99,6 +96,5 @@ This project is currently in **alpha**. The API should be considered unstable an

## Legal

Offered under the [Apache 2 license][badges_license].
Offered under the [Apache 2 license](LICENSE).

[badges_license]: https://github.com/bufbuild/knit-go/blob/main/LICENSE
2 changes: 1 addition & 1 deletion balancer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ func TestConnManager(t *testing.T) {
func TestBalancer_BasicConnManagement(t *testing.T) {
t.Parallel()
pool := balancertesting.NewFakeConnPool()
balancer := newBalancer(context.Background(), balancertesting.NewFakePicker, health.NoOpChecker, pool)
balancer := newBalancer(context.Background(), balancertesting.NewFakePicker, health.NopChecker, pool)
balancer.updateHook = balancertesting.DeterministicReconciler
balancer.start()
// Initial resolve
Expand Down
21 changes: 12 additions & 9 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,20 @@ var (
defaultResolver = resolver.NewDNSResolver(net.DefaultResolver, "ip", defaultNameTTL)
)

// Client is an HTTP client that includes client-side load balancing logic. It
// embeds a standard *[http.Client] and exposes some additional operations.
// Client is an HTTP client that supports configurable client-side load
// balancing, name resolution, and subsetting. It embeds the standard library's
// *[http.Client] and exposes some additional operations.
//
// If working with a library that requires an *[http.Client], simply use the
// embedded Client field. If working with a library that requires an
// [http.RoundTripper], use the Transport field.
// If working with a library that requires an *[http.Client], use the embedded
// Client. If working with a library that requires an [http.RoundTripper], use
// the Transport field.
type Client struct {
*http.Client
}

// NewClient returns a new HTTP client that uses the given options.
// NewClient constructs a new HTTP client optimized for server-to-server
// communication. By default, the client re-resolves addresses every 5 minutes
// and uses a round-robin load balancing policy.
func NewClient(options ...ClientOption) *Client {
var opts clientOptions
for _, opt := range options {
Expand All @@ -65,8 +68,8 @@ func NewClient(options ...ClientOption) *Client {
}
}

// Close closes the HTTP client, releasing any resources and stopping
// any associated background goroutines.
// Close the HTTP client, releasing any resources and stopping any associated
// background goroutines.
func (c *Client) Close() error {
transport, ok := c.Transport.(*mainTransport)
if !ok {
Expand Down Expand Up @@ -400,7 +403,7 @@ func (opts *clientOptions) applyDefaults() {
opts.newPicker = picker.NewRoundRobin
}
if opts.healthChecker == nil {
opts.healthChecker = health.NoOpChecker
opts.healthChecker = health.NopChecker
}
if opts.dialFunc == nil {
opts.dialFunc = defaultDialer.DialContext
Expand Down
14 changes: 7 additions & 7 deletions health/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ import (

//nolint:gochecknoglobals
var (
// NoOpChecker is a checker implementation that does nothing. It assumes
// NopChecker is a checker implementation that does nothing. It assumes
// the state of all connections is healthy.
NoOpChecker Checker = noOpChecker{}
NopChecker Checker = nopChecker{}
)

// Checker manages health checks. It creates new checking processes as new
Expand All @@ -48,15 +48,15 @@ type Tracker interface {
UpdateHealthState(conn.Conn, State)
}

type noOpChecker struct{}
type nopChecker struct{}

func (n noOpChecker) New(_ context.Context, conn conn.Conn, tracker Tracker) io.Closer {
func (n nopChecker) New(_ context.Context, conn conn.Conn, tracker Tracker) io.Closer {
go tracker.UpdateHealthState(conn, StateHealthy)
return noOpCloser{}
return nopCloser{}
}

type noOpCloser struct{}
type nopCloser struct{}

func (n noOpCloser) Close() error {
func (n nopCloser) Close() error {
return nil
}
14 changes: 7 additions & 7 deletions overhead_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,24 @@ import (
"github.com/stretchr/testify/require"
)

type noopTransport struct{}
type nopTransport struct{}

func (n noopTransport) NewRoundTripper(string, string, TransportConfig) RoundTripperResult {
func (n nopTransport) NewRoundTripper(string, string, TransportConfig) RoundTripperResult {
return RoundTripperResult{
RoundTripper: n,
}
}

func (noopTransport) RoundTrip(*http.Request) (*http.Response, error) {
func (nopTransport) RoundTrip(*http.Request) (*http.Response, error) {
response := new(http.Response)
response.StatusCode = 200
response.Body = http.NoBody
return response, nil
}

func BenchmarkNoOpTransportHTTPLB(b *testing.B) {
func BenchmarkNopTransportHTTPLB(b *testing.B) {
client := NewClient(
WithTransport("http", noopTransport{}),
WithTransport("http", nopTransport{}),
WithAllowBackendTarget("http", "localhost:0"),
)
warmCtx, cancel := context.WithTimeout(context.Background(), time.Second)
Expand All @@ -64,9 +64,9 @@ func BenchmarkNoOpTransportHTTPLB(b *testing.B) {
})
}

func BenchmarkNoOpTransportNetHTTP(b *testing.B) {
func BenchmarkNopTransportNetHTTP(b *testing.B) {
client := new(http.Client)
client.Transport = noopTransport{}
client.Transport = nopTransport{}
b.SetParallelism(100)
b.ResetTimer()
b.RunParallel(func(p *testing.PB) {
Expand Down