Skip to content

Commit

Permalink
Merge pull request #4 from Essent/feat/retry-rate-limit
Browse files Browse the repository at this point in the history
feat: retry rate limit
  • Loading branch information
andrei-dobre authored Jan 7, 2025
2 parents ce11382 + ab5d7cd commit b927631
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 10 deletions.
6 changes: 4 additions & 2 deletions internal/provider/data_source_all_usergroups.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"context"
"fmt"

"github.com/essent/terraform-provider-slack/internal/slackExt"

"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
Expand All @@ -21,7 +23,7 @@ func NewAllUserGroupsDataSource() datasource.DataSource {
}

type AllUserGroupsDataSource struct {
client *slack.Client
client slackExt.Client
}

type AllUserGroupsDataSourceModel struct {
Expand Down Expand Up @@ -113,7 +115,7 @@ func (d *AllUserGroupsDataSource) Read(ctx context.Context, req datasource.ReadR
return
}

userGroups, err := d.client.GetUserGroups(slack.GetUserGroupsOptionIncludeUsers(true))
userGroups, err := d.client.GetUserGroups(ctx, slack.GetUserGroupsOptionIncludeUsers(true))
if err != nil {
resp.Diagnostics.AddError(
"Client Error",
Expand Down
5 changes: 3 additions & 2 deletions internal/provider/data_source_all_users.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ import (
"context"
"fmt"

"github.com/essent/terraform-provider-slack/internal/slackExt"

"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/slack-go/slack"
)

var _ datasource.DataSource = &AllUsersDataSource{}
Expand All @@ -21,7 +22,7 @@ func NewAllUsersDataSource() datasource.DataSource {
}

type AllUsersDataSource struct {
client *slack.Client
client slackExt.Client
}

type AllUsersDataSourceModel struct {
Expand Down
8 changes: 5 additions & 3 deletions internal/provider/data_source_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"context"
"fmt"

"github.com/essent/terraform-provider-slack/internal/slackExt"

"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
Expand All @@ -24,7 +26,7 @@ func NewUserDataSource() datasource.DataSource {
}

type UserDataSource struct {
client *slack.Client
client slackExt.Client
}

type UserDataSourceModel struct {
Expand Down Expand Up @@ -95,9 +97,9 @@ func (d *UserDataSource) Read(ctx context.Context, req datasource.ReadRequest, r
)

if !data.ID.IsNull() {
user, err = d.client.GetUserInfo(data.ID.ValueString())
user, err = d.client.GetUserInfo(ctx, data.ID.ValueString())
} else {
user, err = d.client.GetUserByEmail(data.Email.ValueString())
user, err = d.client.GetUserByEmail(ctx, data.Email.ValueString())
}

if err != nil {
Expand Down
8 changes: 5 additions & 3 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"fmt"
"os"

"github.com/essent/terraform-provider-slack/internal/slackExt"

"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/function"
"github.com/hashicorp/terraform-plugin-framework/provider"
Expand All @@ -30,7 +32,7 @@ type SlackProviderModel struct {
}

type SlackProviderData struct {
Client *slack.Client
Client slackExt.Client
}

func (p *SlackProvider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) {
Expand Down Expand Up @@ -83,8 +85,8 @@ func (p *SlackProvider) Configure(ctx context.Context, req provider.ConfigureReq
return
}

resp.DataSourceData = &SlackProviderData{Client: client}
resp.ResourceData = &SlackProviderData{Client: client}
resp.DataSourceData = &SlackProviderData{Client: slackExt.New(client)}
resp.ResourceData = &SlackProviderData{Client: slackExt.New(client)}
}

func (p *SlackProvider) Resources(ctx context.Context) []func() resource.Resource {
Expand Down
18 changes: 18 additions & 0 deletions internal/slackExt/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package slackExt

import (
"context"

"github.com/slack-go/slack"
)

type Client interface {
GetUserInfo(ctx context.Context, user string) (*slack.User, error)
GetUserByEmail(ctx context.Context, email string) (*slack.User, error)
GetUsersContext(ctx context.Context) ([]slack.User, error)
GetUserGroups(ctx context.Context, options ...slack.GetUserGroupsOption) ([]slack.UserGroup, error)
}

func New(base *slack.Client) Client {
return &clientRateLimit{&clientImpl{base}}
}
27 changes: 27 additions & 0 deletions internal/slackExt/client_impl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package slackExt

import (
"context"

"github.com/slack-go/slack"
)

type clientImpl struct {
base *slack.Client
}

func (c *clientImpl) GetUserInfo(ctx context.Context, user string) (*slack.User, error) {
return c.base.GetUserInfoContext(ctx, user)
}

func (c *clientImpl) GetUserByEmail(ctx context.Context, email string) (*slack.User, error) {
return c.base.GetUserByEmailContext(ctx, email)
}

func (c *clientImpl) GetUsersContext(ctx context.Context) ([]slack.User, error) {
return c.base.GetUsersContext(ctx)
}

func (c *clientImpl) GetUserGroups(ctx context.Context, options ...slack.GetUserGroupsOption) ([]slack.UserGroup, error) {
return c.base.GetUserGroupsContext(ctx, options...)
}
54 changes: 54 additions & 0 deletions internal/slackExt/client_rate_limit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package slackExt

import (
"context"
"time"

"github.com/slack-go/slack"
)

type clientRateLimit struct {
base Client
}

func rateLimit[R any](ctx context.Context, f func() (R, error), getZeroValue func() R) (result R, err error) {
for {
result, err = f()

if err == nil {
return result, nil
}

if rateLimitedError, ok := err.(*slack.RateLimitedError); ok {
select {
case <-time.After(rateLimitedError.RetryAfter):
case <-ctx.Done():
return getZeroValue(), ctx.Err()
}
} else {
return getZeroValue(), err
}
}
}

func (c *clientRateLimit) GetUserInfo(ctx context.Context, user string) (result *slack.User, err error) {
return rateLimit(ctx, func() (*slack.User, error) {
return c.base.GetUserInfo(ctx, user)
}, func() *slack.User { return nil })
}

func (c *clientRateLimit) GetUserByEmail(ctx context.Context, email string) (*slack.User, error) {
return rateLimit(ctx, func() (*slack.User, error) {
return c.base.GetUserByEmail(ctx, email)
}, func() *slack.User { return nil })
}

func (c *clientRateLimit) GetUsersContext(ctx context.Context) ([]slack.User, error) {
return c.base.GetUsersContext(ctx)
}

func (c *clientRateLimit) GetUserGroups(ctx context.Context, options ...slack.GetUserGroupsOption) ([]slack.UserGroup, error) {
return rateLimit(ctx, func() ([]slack.UserGroup, error) {
return c.base.GetUserGroups(ctx, options...)
}, func() []slack.UserGroup { return []slack.UserGroup{} })
}

0 comments on commit b927631

Please sign in to comment.