Skip to content

Commit 3c3c365

Browse files
sfe: Periodically import approved rate limit override tickets (#8372)
1 parent 6c16784 commit 3c3c365

File tree

6 files changed

+851
-6
lines changed

6 files changed

+851
-6
lines changed

cmd/sfe/main.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"flag"
66
"net/http"
77
"os"
8+
"sync"
89

910
"github.com/jmhodges/clock"
1011

@@ -78,6 +79,21 @@ type Config struct {
7879
// in this file must be identical to those in the RA.
7980
Defaults string `validate:"required_with=Redis"`
8081
}
82+
83+
// OverridesImporter configures the periodic import of approved rate
84+
// limit override requests from Zendesk.
85+
OverridesImporter struct {
86+
// Mode controls which tickets are processed. Valid values are:
87+
// - "all": process all tickets
88+
// - "even": process only tickets with even IDs
89+
// - "odd": process only tickets with odd IDs
90+
// If unspecified or empty, defaults to "all".
91+
Mode string `validate:"omitempty,required_with=Interval,oneof=all even odd"`
92+
// Interval is the amount of time between runs of the importer. If
93+
// zero or unspecified, the importer is disabled. Minimum value is
94+
// 20 minutes.
95+
Interval config.Duration `validate:"omitempty,required_with=Mode,min=1200s"`
96+
} `validate:"omitempty,dive"`
8197
Features features.Config
8298
}
8399

@@ -141,6 +157,8 @@ func main() {
141157
}
142158

143159
var zendeskClient *zendesk.Client
160+
var overridesImporterShutdown func()
161+
var overridesImporterWG sync.WaitGroup
144162
if c.SFE.Zendesk != nil {
145163
zendeskToken, err := c.SFE.Zendesk.Token.Pass()
146164
cmd.FailOnError(err, "Failed to load Zendesk token")
@@ -162,6 +180,30 @@ func main() {
162180
if err != nil {
163181
cmd.FailOnError(err, "Failed to create Zendesk client")
164182
}
183+
184+
if c.SFE.OverridesImporter.Interval.Duration > 0 {
185+
mode := sfe.ProcessMode(c.SFE.OverridesImporter.Mode)
186+
if mode == "" {
187+
mode = sfe.ProcessAll
188+
}
189+
190+
importer, err := sfe.NewOverridesImporter(
191+
mode,
192+
c.SFE.OverridesImporter.Interval.Duration,
193+
zendeskClient,
194+
rac,
195+
clk,
196+
logger,
197+
)
198+
cmd.FailOnError(err, "Creating overrides importer")
199+
200+
var ctx context.Context
201+
ctx, overridesImporterShutdown = context.WithCancel(context.Background())
202+
overridesImporterWG.Go(func() {
203+
importer.Start(ctx)
204+
})
205+
logger.Infof("Overrides importer started with mode=%s interval=%s", mode, c.SFE.OverridesImporter.Interval.Duration)
206+
}
165207
}
166208

167209
var limiter *ratelimits.Limiter
@@ -211,6 +253,10 @@ func main() {
211253
defer func() {
212254
ctx, cancel := context.WithTimeout(context.Background(), c.SFE.ShutdownStopTimeout.Duration)
213255
defer cancel()
256+
if overridesImporterShutdown != nil {
257+
overridesImporterShutdown()
258+
overridesImporterWG.Wait()
259+
}
214260
_ = srv.Shutdown(ctx)
215261
oTelShutdown(ctx)
216262
}()

sfe/overrides.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ const (
4747
// reviewStatusDefault is the initial status of a ticket when created.
4848
reviewStatusDefault = "review-status-pending"
4949

50+
// reviewStatusApproved is the status of a ticket when it has been approved.
51+
reviewStatusApproved = "review-status-approved"
52+
5053
// validateOverrideFieldBodyLimit is the maximum size of request body
5154
// accepted by validateOverrideFieldHandler. It should be large enough to
5255
// accommodate the JSON encoded validationRequest struct, but small enough

sfe/overrides_test.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@ const (
2121
apiToken = "someToken"
2222
)
2323

24-
func createFakeZendeskClientServer(t *testing.T) *zendesk.Client {
24+
func createFakeZendeskClientServer(t *testing.T) (*zendeskfake.Server, *zendesk.Client) {
2525
t.Helper()
2626

27-
ts := httptest.NewServer(zendeskfake.NewServer(apiTokenEmail, apiToken, nil).Handler())
27+
server := zendeskfake.NewServer(apiTokenEmail, apiToken, nil)
28+
ts := httptest.NewServer(server.Handler())
2829
t.Cleanup(ts.Close)
2930

3031
client, err := zendesk.NewClient(ts.URL, apiTokenEmail, apiToken, map[string]int64{
@@ -39,7 +40,7 @@ func createFakeZendeskClientServer(t *testing.T) *zendesk.Client {
3940
if err != nil {
4041
t.Errorf("NewClient(%q) returned error: %s", ts.URL, err)
4142
}
42-
return client
43+
return server, client
4344
}
4445

4546
func minimalTemplates(t *testing.T) *template.Template {
@@ -142,7 +143,7 @@ func TestSubmitOverrideRequestHandlerErrors(t *testing.T) {
142143

143144
sfe, _ := setupSFE(t)
144145
sfe.templatePages = minimalTemplates(t)
145-
client := createFakeZendeskClientServer(t)
146+
_, client := createFakeZendeskClientServer(t)
146147
sfe.zendeskClient = client
147148
mockPardotClient, mockImpl := mocks.NewMockPardotClientImpl()
148149
sfe.ee = mocks.NewMockExporterImpl(mockPardotClient)
@@ -190,7 +191,7 @@ func TestSubmitOverrideRequestHandlerSuccess(t *testing.T) {
190191

191192
sfe, _ := setupSFE(t)
192193
sfe.templatePages = minimalTemplates(t)
193-
client := createFakeZendeskClientServer(t)
194+
_, client := createFakeZendeskClientServer(t)
194195
sfe.zendeskClient = client
195196

196197
// All of these fields are perfectly valid.
@@ -429,7 +430,7 @@ func TestSubmitOverrideRequestHandlerRateLimited(t *testing.T) {
429430

430431
sfe, _ := setupSFE(t)
431432
sfe.templatePages = minimalTemplates(t)
432-
client := createFakeZendeskClientServer(t)
433+
_, client := createFakeZendeskClientServer(t)
433434
sfe.zendeskClient = client
434435

435436
for attempt := range 101 {

0 commit comments

Comments
 (0)