@@ -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+ // On Create we poll GetOrgPreferences until it succeeds; UpdateOrgPreferences retries on 401 as a fallback.
83+ const (
84+ orgPrefsReadinessTimeout = 3 * time .Minute
85+ orgPrefsReadinessPoll = 2 * time .Second
86+ orgPrefsRetryAttempts = 12
87+ orgPrefsRetryDelay = 5 * time .Second
88+ )
8589
8690func isRetryableOrgPrefs401 (err error ) bool {
8791 if err == nil {
@@ -96,8 +100,30 @@ 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+ // 401 means the org context is not ready yet (membership propagation).
105+ func waitForOrgPreferencesReadable (ctx context.Context , client * goapi.GrafanaHTTPAPI ) error {
106+ deadline := time .Now ().Add (orgPrefsReadinessTimeout )
107+ var lastErr error
108+ for time .Now ().Before (deadline ) {
109+ _ , err := client .OrgPreferences .GetOrgPreferences ()
110+ if err == nil {
111+ return nil
112+ }
113+ lastErr = err
114+ if ! isRetryableOrgPrefs401 (err ) {
115+ return err
116+ }
117+ select {
118+ case <- ctx .Done ():
119+ return ctx .Err ()
120+ case <- time .After (orgPrefsReadinessPoll ):
121+ }
122+ }
123+ return lastErr
124+ }
125+
99126// 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.
101127func updateOrgPreferencesWithRetryWithDelay (ctx context.Context , client * goapi.GrafanaHTTPAPI , body * models.UpdatePrefsCmd , initialDelay time.Duration ) error {
102128 if initialDelay > 0 {
103129 select {
@@ -185,13 +211,16 @@ func (r *organizationPreferencesResource) Create(ctx context.Context, req resour
185211 timezone := data .Timezone .ValueString ()
186212 weekStart := data .WeekStart .ValueString ()
187213
188- // Initial delay for new orgs so Grafana can propagate membership before first API call.
214+ if err := waitForOrgPreferencesReadable (ctx , client ); err != nil {
215+ resp .Diagnostics .AddError ("Organization is not ready to update preferences yet" , err .Error ())
216+ return
217+ }
189218 err = updateOrgPreferencesWithRetryWithDelay (ctx , client , & models.UpdatePrefsCmd {
190219 Theme : theme ,
191220 HomeDashboardUID : homeDashboardUID ,
192221 Timezone : timezone ,
193222 WeekStart : weekStart ,
194- }, 15 * time . Second )
223+ }, 0 )
195224 if err != nil {
196225 resp .Diagnostics .AddError ("Failed to update organization preferences" , err .Error ())
197226 return
0 commit comments