@@ -79,9 +79,13 @@ func (v weekStartValidator) ValidateString(ctx context.Context, req validator.St
7979}
8080
8181// Grafana may return 401 briefly after creating a new org until the creating user's membership is propagated.
82- // We use an initial delay on Create and retry on 401.
83- const orgPrefsRetryAttempts = 25
84- const orgPrefsRetryDelay = 6 * time .Second
82+ // We poll GET until it succeeds, then PUT with 401 retries (CI: parallel acc tests + new orgs).
83+ const (
84+ orgPrefsReadinessTimeout = 4 * time .Minute
85+ orgPrefsReadinessPoll = 2 * time .Second
86+ orgPrefsRetryAttempts = 30
87+ orgPrefsRetryDelay = 5 * time .Second
88+ )
8589
8690func isRetryableOrgPrefs401 (err error ) bool {
8791 if err == nil {
@@ -96,8 +100,29 @@ func isRetryableOrgPrefs401(err error) bool {
96100 return strings .Contains (errStr , "401" ) || strings .Contains (errStr , "Unauthorized" )
97101}
98102
103+ // waitForOrgPreferencesReadable polls GET /org/preferences until it succeeds or a non-retryable error occurs.
104+ func waitForOrgPreferencesReadable (ctx context.Context , client * goapi.GrafanaHTTPAPI ) error {
105+ deadline := time .Now ().Add (orgPrefsReadinessTimeout )
106+ var lastErr error
107+ for time .Now ().Before (deadline ) {
108+ _ , err := client .OrgPreferences .GetOrgPreferences ()
109+ if err == nil {
110+ return nil
111+ }
112+ lastErr = err
113+ if ! isRetryableOrgPrefs401 (err ) {
114+ return err
115+ }
116+ select {
117+ case <- ctx .Done ():
118+ return ctx .Err ()
119+ case <- time .After (orgPrefsReadinessPoll ):
120+ }
121+ }
122+ return lastErr
123+ }
124+
99125// updateOrgPreferencesWithRetryWithDelay calls UpdateOrgPreferences with optional initial delay and retries on 401.
100- // initialDelay is used on Create to give new orgs time for membership to propagate before the first attempt.
101126func updateOrgPreferencesWithRetryWithDelay (ctx context.Context , client * goapi.GrafanaHTTPAPI , body * models.UpdatePrefsCmd , initialDelay time.Duration ) error {
102127 if initialDelay > 0 {
103128 select {
@@ -185,13 +210,16 @@ func (r *organizationPreferencesResource) Create(ctx context.Context, req resour
185210 timezone := data .Timezone .ValueString ()
186211 weekStart := data .WeekStart .ValueString ()
187212
188- // Initial delay for new orgs so Grafana can propagate membership before first API call.
213+ if err := waitForOrgPreferencesReadable (ctx , client ); err != nil {
214+ resp .Diagnostics .AddError ("Organization is not ready to update preferences yet" , err .Error ())
215+ return
216+ }
189217 err = updateOrgPreferencesWithRetryWithDelay (ctx , client , & models.UpdatePrefsCmd {
190218 Theme : theme ,
191219 HomeDashboardUID : homeDashboardUID ,
192220 Timezone : timezone ,
193221 WeekStart : weekStart ,
194- }, 15 * time . Second )
222+ }, 0 )
195223 if err != nil {
196224 resp .Diagnostics .AddError ("Failed to update organization preferences" , err .Error ())
197225 return
0 commit comments