Skip to content

Commit 2a4827f

Browse files
Add rate limiting and retry configuration to Contentstack provider
- Add rate_limit, rate_burst, and max_retries provider attributes - Update provider schema to support new rate limiting options - Add automatic retry logic integration with contentstack-go-sdk - Update provider documentation with new attributes - Add simplified examples for provider and rate-limiting configurations - Update go.mod to use enhanced contentstack-go-sdk with rate limiting This enables reliable Terraform operations by automatically handling Contentstack API rate limits (10 req/sec) with configurable throttling and exponential backoff retry logic for 429 responses. Related: contentstack-go-sdk rate limiting implementation
1 parent 024f4a0 commit 2a4827f

File tree

7 files changed

+87
-10
lines changed

7 files changed

+87
-10
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@
1010
/.idea
1111
/.vscode
1212
/local
13+
.DS_Store

docs/index.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,6 @@ description: |-
2222
- `base_url` (String) The BaseURL, e.g. https://eu-api.contentstack.com/. See https://www.contentstack.com/docs/developers/apis/content-management-api/#base-url
2323
- `branch` (String) The branch to manage resources in. If not specified, the main branch will be used.
2424
- `management_token` (String, Sensitive) Management Tokens are stack-level tokens, with no users attached to them.
25+
- `max_retries` (Number) The maximum number of retry attempts for 429 (rate limit) responses. Defaults to 3. Uses exponential backoff: 1s, 2s, 4s, 8s, 16s, capped at 30s.
26+
- `rate_burst` (Number) The maximum burst size for rate limiting. Defaults to 10. This allows short bursts of requests above the rate limit.
27+
- `rate_limit` (Number) The maximum number of requests per second to the Contentstack API. Defaults to 10.0 to comply with API limits. Set to 0 to disable rate limiting.

examples/provider/main.tf

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
terraform {
2+
required_providers {
3+
contentstack = {
4+
source = "labd/contentstack"
5+
}
6+
}
7+
}
8+
9+
provider "contentstack" {
10+
base_url = "https://api.contentstack.io"
11+
api_key = "<api_key>"
12+
management_token = "<management_token>"
13+
branch = "main"
14+
}

examples/rate-limiting/main.tf

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
terraform {
2+
required_providers {
3+
contentstack = {
4+
source = "labd/contentstack"
5+
}
6+
}
7+
}
8+
9+
provider "contentstack" {
10+
base_url = "https://api.contentstack.io"
11+
api_key = "<api_key>"
12+
management_token = "<management_token>"
13+
14+
rate_limit = 8.0
15+
rate_burst = 5
16+
max_retries = 3
17+
}
18+
19+
resource "contentstack_content_type" "example" {
20+
title = "Example Content Type"
21+
uid = "example"
22+
23+
schema = jsonencode([
24+
{
25+
display_name = "Title"
26+
uid = "title"
27+
data_type = "text"
28+
mandatory = true
29+
}
30+
])
31+
}

go.mod

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
module github.com/labd/terraform-provider-contentstack
22

3-
go 1.18
3+
go 1.24.0
4+
5+
toolchain go1.24.3
46

57
require (
68
github.com/hashicorp/terraform-plugin-docs v0.9.0
@@ -59,6 +61,7 @@ require (
5961
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect
6062
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
6163
golang.org/x/text v0.3.7 // indirect
64+
golang.org/x/time v0.13.0 // indirect
6265
google.golang.org/appengine v1.6.6 // indirect
6366
google.golang.org/genproto v0.0.0-20200711021454-869866162049 // indirect
6467
google.golang.org/grpc v1.46.0 // indirect

go.sum

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
5252
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
5353
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
5454
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
55+
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
5556
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
5657
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
5758
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
@@ -149,21 +150,19 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOl
149150
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
150151
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
151152
github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE=
153+
github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74=
152154
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck=
153155
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
154156
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
155157
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
156158
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
157159
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
160+
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
158161
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
159162
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
160163
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
161164
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
162165
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
163-
github.com/labd/contentstack-go-sdk v0.1.0 h1:lxBbGBkIlileNn2+VrVG6XP776Llxy9i4THPBA01xTU=
164-
github.com/labd/contentstack-go-sdk v0.1.0/go.mod h1:J17aqV8NOcmFfkkotnAljlt6Ctwlu21Ieeo/0BPLNtg=
165-
github.com/labd/contentstack-go-sdk v0.1.0 h1:lxBbGBkIlileNn2+VrVG6XP776Llxy9i4THPBA01xTU=
166-
github.com/labd/contentstack-go-sdk v0.1.0/go.mod h1:J17aqV8NOcmFfkkotnAljlt6Ctwlu21Ieeo/0BPLNtg=
167166
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
168167
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
169168
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
@@ -190,6 +189,7 @@ github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zx
190189
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
191190
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
192191
github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce h1:RPclfga2SEJmgMmz2k+Mg7cowZ8yv4Trqw9UsJby758=
192+
github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce/go.mod h1:uFMI8w+ref4v2r9jz+c9i1IfIttS/OkmLfrk1jne5hs=
193193
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
194194
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
195195
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -202,11 +202,13 @@ github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSg
202202
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
203203
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
204204
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
205+
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
205206
github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww=
206207
github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
207208
github.com/sebdah/goldie v1.0.0/go.mod h1:jXP4hmWywNEwZzhMuv2ccnqTSFpuq8iyQhtQdkkZBH4=
208209
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
209210
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
211+
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
210212
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
211213
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
212214
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
@@ -304,6 +306,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
304306
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
305307
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
306308
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
309+
golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI=
310+
golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
307311
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
308312
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
309313
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=

internal/provider/provider.go

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,17 +53,35 @@ func (p *provider) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics)
5353
Optional: true,
5454
Description: "The branch to manage resources in. If not specified, the main branch will be used.",
5555
},
56+
"rate_limit": {
57+
Type: types.Float64Type,
58+
Optional: true,
59+
Description: "The maximum number of requests per second to the Contentstack API. Defaults to 10.0 to comply with API limits. Set to 0 to disable rate limiting.",
60+
},
61+
"rate_burst": {
62+
Type: types.Int64Type,
63+
Optional: true,
64+
Description: "The maximum burst size for rate limiting. Defaults to 10. This allows short bursts of requests above the rate limit.",
65+
},
66+
"max_retries": {
67+
Type: types.Int64Type,
68+
Optional: true,
69+
Description: "The maximum number of retry attempts for 429 (rate limit) responses. Defaults to 3. Uses exponential backoff: 1s, 2s, 4s, 8s, 16s, capped at 30s.",
70+
},
5671
},
5772
}, nil
5873
}
5974

6075
// Provider schema struct
6176
type providerData struct {
62-
BaseURL types.String `tfsdk:"base_url"`
63-
AuthToken types.String `tfsdk:"auth_token"`
64-
ApiKey types.String `tfsdk:"api_key"`
65-
ManagementToken types.String `tfsdk:"management_token"`
66-
Branch types.String `tfsdk:"branch"`
77+
BaseURL types.String `tfsdk:"base_url"`
78+
AuthToken types.String `tfsdk:"auth_token"`
79+
ApiKey types.String `tfsdk:"api_key"`
80+
ManagementToken types.String `tfsdk:"management_token"`
81+
Branch types.String `tfsdk:"branch"`
82+
RateLimit types.Float64 `tfsdk:"rate_limit"`
83+
RateBurst types.Int64 `tfsdk:"rate_burst"`
84+
MaxRetries types.Int64 `tfsdk:"max_retries"`
6785
}
6886

6987
func (p *provider) Configure(ctx context.Context, req tfsdk.ConfigureProviderRequest, resp *tfsdk.ConfigureProviderResponse) {
@@ -82,6 +100,9 @@ func (p *provider) Configure(ctx context.Context, req tfsdk.ConfigureProviderReq
82100
HTTPClient: &http.Client{
83101
Transport: management.DebugTransport,
84102
},
103+
RateLimit: config.RateLimit.Value,
104+
RateBurst: int(config.RateBurst.Value),
105+
MaxRetries: int(config.MaxRetries.Value),
85106
}
86107

87108
c, err := management.NewClient(cfg)

0 commit comments

Comments
 (0)