(ctx context.Context, diffs StorageDiff)
| 224 | } |
| 225 | |
| 226 | func (c *userClient) ApplyStorageDiff(ctx context.Context, diffs StorageDiff) error { |
| 227 | ae := serializer.NewAggregateError() |
| 228 | for uid, diff := range diffs { |
| 229 | // Retry logic for MySQL deadlock (Error 1213) |
| 230 | // This is a temporary workaround. TODO: optimize storage mutation |
| 231 | maxRetries := 3 |
| 232 | var lastErr error |
| 233 | for attempt := 0; attempt < maxRetries; attempt++ { |
| 234 | if err := c.client.User.Update().Where(user.ID(uid)).AddStorage(diff).Exec(ctx); err != nil { |
| 235 | lastErr = err |
| 236 | // Check if it's a MySQL deadlock error (Error 1213) |
| 237 | if strings.Contains(err.Error(), "Error 1213") && attempt < maxRetries-1 { |
| 238 | // Wait a bit before retrying with exponential backoff |
| 239 | time.Sleep(time.Duration(attempt+1) * 10 * time.Millisecond) |
| 240 | continue |
| 241 | } |
| 242 | ae.Add(fmt.Sprintf("%d", uid), fmt.Errorf("failed to apply storage diff for user %d: %w", uid, err)) |
| 243 | break |
| 244 | } |
| 245 | // Success, break out of retry loop |
| 246 | lastErr = nil |
| 247 | break |
| 248 | } |
| 249 | |
| 250 | if lastErr != nil { |
| 251 | ae.Add(fmt.Sprintf("%d", uid), fmt.Errorf("failed to apply storage diff for user %d: %w", uid, lastErr)) |
| 252 | } |
| 253 | } |
| 254 | |
| 255 | return ae.Aggregate() |
| 256 | } |
| 257 | |
| 258 | func (c *userClient) CalculateStorage(ctx context.Context, uid int) (int64, error) { |
| 259 | var sum int64 |
nothing calls this directly
no test coverage detected