Skip to content

Shard notification hub#54

Open
lizard-boy wants to merge 37 commits into
mainfrom
shard-notification-hub
Open

Shard notification hub#54
lizard-boy wants to merge 37 commits into
mainfrom
shard-notification-hub

Conversation

@lizard-boy

@lizard-boy lizard-boy commented Oct 19, 2024

Copy link
Copy Markdown

🎟️ Tracking

https://bitwarden.atlassian.net/browse/PM-9452

📔 Objective

Reworks notification hub sharding to be based on the date of GUID comb creation and a binning algorithm.

This change is needed so that we can keep track of the installation location of each device, which is needed for updates related to changes to a device's

  1. Token
  2. User Organizations
  3. User authentication

⏰ Reminders before review

  • Contributor guidelines followed
  • All formatters and local linters executed and passed
  • Written new unit and / or integration tests where applicable
  • Protected functional changes with optionality (feature flags)
  • Used internationalization (i18n) for all UI strings
  • CI builds passed
  • Communicated to DevOps any deployment requirements
  • Updated any necessary documentation (Confluence, contributing docs) or informed the documentation team

🦮 Reviewer guidelines

  • 👍 (:+1:) or similar for great changes
  • 📝 (:memo:) or ℹ️ (:information_source:) for notes or general info
  • ❓ (:question:) for questions
  • 🤔 (:thinking:) or 💭 (:thought_balloon:) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion
  • 🎨 (:art:) for suggestions / improvements
  • ❌ (:x:) or ⚠️ (:warning:) for more significant problems or concerns needing attention
  • 🌱 (:seedling:) or ♻️ (:recycle:) for future improvements or indications of technical debt
  • ⛏ (:pick:) for minor or nitpick changes

Greptile Summary

This pull request implements a significant rework of the notification hub sharding mechanism, focusing on GUID comb creation dates and a binning algorithm for improved device management.

  • Introduced NotificationHubPool and NotificationHubConnection classes for managing multiple notification hub clients
  • Removed DeviceType parameter from various methods, simplifying push notification and registration interfaces
  • Added new interfaces INotificationHubProxy and INotificationHubPool for better abstraction of notification hub operations
  • Implemented CoreHelpers.DateFromComb and CoreHelpers.BinForComb methods to support the new sharding mechanism
  • Updated GlobalSettings to include NotificationHubPoolSettings with registration start and end dates for each hub

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

29 file(s) reviewed, 45 comment(s)
Edit PR Review Bot Settings | Greptile

{
CheckUsage();
await _pushRegistrationService.DeleteRegistrationAsync(Prefix(model.Id), model.Type);
await _pushRegistrationService.DeleteRegistrationAsync(Prefix(model.Id));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Removal of device type parameter may affect how different device types are handled during deletion

Comment on lines 56 to 58
await _pushRegistrationService.AddUserRegistrationOrganizationAsync(
model.Devices.Select(d => new KeyValuePair<string, Core.Enums.DeviceType>(Prefix(d.Id), d.Type)),
model.Devices.Select(d => Prefix(d.Id)),
Prefix(model.OrganizationId));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Device type information is no longer passed to AddUserRegistrationOrganizationAsync, which could impact device-specific organization management

Comment on lines 65 to 67
await _pushRegistrationService.DeleteUserRegistrationOrganizationAsync(
model.Devices.Select(d => new KeyValuePair<string, Core.Enums.DeviceType>(Prefix(d.Id), d.Type)),
model.Devices.Select(d => Prefix(d.Id)),
Prefix(model.OrganizationId));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Similar to the add-organization endpoint, device type information is removed from DeleteUserRegistrationOrganizationAsync

Comment on lines 1839 to 1841
.Where(d => !string.IsNullOrWhiteSpace(d.PushToken))
.Select(d => new KeyValuePair<string, DeviceType>(d.Id.ToString(), d.Type));
.Select(d => d.Id.ToString());
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: The Select statement now only returns the device ID as a string, omitting the DeviceType. Ensure this doesn't break any code that previously relied on the device type information.

{
return deviceId != null && deviceId.Length == 73 && deviceId[36] == '_';
}
public static bool TryParse(string deviceId, out InstallationDeviceEntity installationDeviceEntity)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: consider adding XML documentation for this public method

Comment on lines +199 to +200
// Act
var result = connection.RegistrationEnabled(CoreHelpers.GenerateComb(Guid.NewGuid(), DateTime.UtcNow.AddHours(1)));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Test might be sensitive to execution time. Consider using fixed timestamps

Comment on lines +85 to +86
RegistrationStartDate = null,
RegistrationEndDate = null,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Test might not accurately represent a scenario with no valid hubs. Consider setting dates to the past


[Theory]
[MemberData(nameof(ClientMethods))]
public async void CallsAllClients(Func<NotificationHubClientProxy, Task> proxyMethod, Func<INotificationHubClient, Task> clientMethod)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Use Task instead of async void for better error handling

[MemberData(nameof(ClientMethods))]
public async void CallsAllClients(Func<NotificationHubClientProxy, Task> proxyMethod, Func<INotificationHubClient, Task> clientMethod)
{
var clients = _clients.ToArray();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Ensure _clients is not empty before converting to array

private readonly ILogger<MultiServicePushNotificationService> _logger;
private readonly ILogger<RelayPushNotificationService> _relayLogger;
private readonly ILogger<NotificationsApiPushNotificationService> _hubLogger;
private readonly IEnumerable<IPushNotificationService> _services;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Consider using a more specific type like IList instead of IEnumerable for better control over the collection

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants