UserLookup.cs
2,409 bytes
| 1 | using Microsoft.Extensions.Logging; |
|---|---|
| 2 | using Microsoft.Extensions.Options; |
| 3 | using SplitApp.Shared.Contracts.Users; |
| 4 | |
| 5 | namespace SplitApp.Shared.Messaging.Integration.Users; |
| 6 | |
| 7 | /// <summary> |
| 8 | /// Default <see cref="IUserLookup"/> backed by <see cref="IMessageBus"/> RPC. |
| 9 | /// Empty input collections short-circuit without a network round-trip. |
| 10 | /// On bus failure (timeout / unavailable) returns an empty result and logs — the |
| 11 | /// UX shows "(unknown)" rather than crashing the page. |
| 12 | /// </summary> |
| 13 | public class UserLookup : IUserLookup |
| 14 | { |
| 15 | private readonly IMessageBus _bus; |
| 16 | private readonly MessagingOptions _options; |
| 17 | private readonly ILogger<UserLookup> _logger; |
| 18 | |
| 19 | public UserLookup(IMessageBus bus, IOptions<MessagingOptions> options, ILogger<UserLookup> logger) |
| 20 | { |
| 21 | _bus = bus; |
| 22 | _options = options.Value; |
| 23 | _logger = logger; |
| 24 | } |
| 25 | |
| 26 | public async Task<UserDto?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default) |
| 27 | { |
| 28 | if (id == Guid.Empty) return null; |
| 29 | try |
| 30 | { |
| 31 | return await _bus.RequestAsync<GetUserByIdRequest, UserDto?>( |
| 32 | new GetUserByIdRequest(id), |
| 33 | TimeSpan.FromSeconds(_options.RpcReplyTimeoutSeconds), |
| 34 | cancellationToken); |
| 35 | } |
| 36 | catch (Exception ex) when (ex is MessageBusTimeoutException or MessageBusUnavailableException) |
| 37 | { |
| 38 | _logger.LogWarning(ex, "User lookup degraded for {Id}", id); |
| 39 | return null; |
| 40 | } |
| 41 | } |
| 42 | |
| 43 | public async Task<IReadOnlyDictionary<Guid, UserDto>> GetByIdsAsync( |
| 44 | IEnumerable<Guid> ids, |
| 45 | CancellationToken cancellationToken = default) |
| 46 | { |
| 47 | var idArr = ids.Where(i => i != Guid.Empty).Distinct().ToArray(); |
| 48 | if (idArr.Length == 0) return new Dictionary<Guid, UserDto>(); |
| 49 | |
| 50 | try |
| 51 | { |
| 52 | var result = await _bus.RequestAsync<GetUsersByIdsRequest, UserDto[]>( |
| 53 | new GetUsersByIdsRequest(idArr), |
| 54 | TimeSpan.FromSeconds(_options.RpcReplyTimeoutSeconds), |
| 55 | cancellationToken); |
| 56 | return result.ToDictionary(u => u.Id); |
| 57 | } |
| 58 | catch (Exception ex) when (ex is MessageBusTimeoutException or MessageBusUnavailableException) |
| 59 | { |
| 60 | _logger.LogWarning(ex, "User batch lookup degraded for {Count} ids", idArr.Length); |
| 61 | return new Dictionary<Guid, UserDto>(); |
| 62 | } |
| 63 | } |
| 64 | } |
| 65 | |