Skip to content

Commit 6bde3ef

Browse files
committed
fix: http client
1 parent 42e3829 commit 6bde3ef

File tree

1 file changed

+34
-23
lines changed

1 file changed

+34
-23
lines changed

pkg/google/google.go

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -305,41 +305,52 @@ func (ds *DirectoryService) GetGroup(ctx context.Context, groupID string) (*admi
305305
}
306306

307307
// GetUsersBatch retrieves multiple users by their email addresses using batch queries.
308-
// This method is optimized for performance by using the ListUsers method with email queries
308+
// This method is optimized for performance by using multiple ListUsers calls with email queries
309309
// instead of making individual GetUser calls.
310310
func (ds *DirectoryService) GetUsersBatch(ctx context.Context, emails []string) ([]*admin.User, error) {
311311
if len(emails) == 0 {
312312
return []*admin.User{}, nil
313313
}
314314

315-
// For large numbers of emails, the OR query might be too complex for Google API
316-
// Use individual GetUser calls as fallback for reliability
317-
if len(emails) > 20 {
318-
return ds.getUsersIndividually(ctx, emails)
319-
}
315+
// Use chunked approach for better reliability and performance
316+
// Optimal chunk size balances API complexity vs number of requests
317+
const chunkSize = 15
320318

321-
// Use ListUsers with email queries for smaller batches
322-
emailQueries := make([]string, len(emails))
323-
for i, email := range emails {
324-
emailQueries[i] = fmt.Sprintf("email:%s", email)
325-
}
319+
var allUsers []*admin.User
326320

327-
// Join queries with OR to get all users in one request
328-
query := strings.Join(emailQueries, " OR ")
321+
// Process emails in chunks to avoid overly complex OR queries
322+
for i := 0; i < len(emails); i += chunkSize {
323+
end := min(i+chunkSize, len(emails))
329324

330-
users, err := ds.ListUsers(ctx, []string{query})
331-
if err != nil {
332-
slog.Warn("google: GetUsersBatch failed, falling back to individual calls", "error", err)
333-
return ds.getUsersIndividually(ctx, emails)
334-
}
325+
chunk := emails[i:end]
326+
327+
// Create OR query for this chunk
328+
emailQueries := make([]string, len(chunk))
329+
for j, email := range chunk {
330+
emailQueries[j] = fmt.Sprintf("email:%s", email)
331+
}
332+
333+
query := strings.Join(emailQueries, " OR ")
335334

336-
// If no users returned but we expected some, fallback to individual calls
337-
if len(users) == 0 && len(emails) > 0 {
338-
slog.Warn("google: GetUsersBatch returned no users, falling back to individual calls", "expected_emails", len(emails))
339-
return ds.getUsersIndividually(ctx, emails)
335+
// Execute ListUsers for this chunk
336+
users, err := ds.ListUsers(ctx, []string{query})
337+
if err != nil {
338+
// If chunk query fails, fall back to individual calls for this chunk only
339+
slog.Warn("google: GetUsersBatch chunk failed, falling back to individual calls for chunk",
340+
"error", err, "chunk_size", len(chunk), "chunk_start", i)
341+
342+
individualUsers, individualErr := ds.getUsersIndividually(ctx, chunk)
343+
if individualErr != nil {
344+
return nil, fmt.Errorf("google: both batch and individual calls failed: batch_error=%w, individual_error=%v", err, individualErr)
345+
}
346+
users = individualUsers
347+
}
348+
349+
// Accumulate results from this chunk
350+
allUsers = append(allUsers, users...)
340351
}
341352

342-
return users, nil
353+
return allUsers, nil
343354
}
344355

345356
// getUsersIndividually retrieves users one by one using GetUser calls

0 commit comments

Comments
 (0)