@@ -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.
310310func (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