Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ex/notifications/notification_server): send notification to all connected Skate instances #2831

Merged

Conversation

firestack
Copy link
Member

@firestack firestack commented Sep 30, 2024

To be able to synchronize multiple Skate instances in production, we need to setup
distributed Elixir.

Following the way https://github.com/mbta/ride_along did it, this uses DNSCluster
to find the other Skate instances, and if the variable is not present, it does nothing
so this is safe to deploy to production before the corresponding DevOps PR.

Depends on:

@firestack firestack changed the title feat(ex/mix): add dns_cluster feat(ex/notifications/notification_server): send notification to all connected Skate instances Sep 30, 2024
@firestack firestack marked this pull request as ready for review September 30, 2024 17:22
@firestack firestack requested a review from a team as a code owner September 30, 2024 17:22
@firestack
Copy link
Member Author

I uhh, didn't mean to put this up for review just yet, as I was looking into if we could add tests. But we could merge without tests because I'm unsure about writing tests for distributed Elixir, I've been looking at https://elixirschool.com/en/lessons/advanced/otp_distribution#conditionally-excluding-tests-with-tags-11 but am still not certain how to do so.

@firestack firestack force-pushed the kf/asn/dn/distributed-notifications branch from a8e98cf to 36cd467 Compare October 1, 2024 20:13
Copy link
Collaborator

@hannahpurcell hannahpurcell left a comment

Choose a reason for hiding this comment

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

Ok! Iiiiii think this makes sense to me and can't think of any feedback, so let's see it in action?

config/dev.exs Show resolved Hide resolved
# send the notification to all instances
for node <- Node.list() do
Node.spawn(node, fn ->
server = Keyword.get(options, :server, default_name())
Copy link
Member

Choose a reason for hiding this comment

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

suggestion: you shouldn't need Node.spawn here. You can target the named server on another node with {process_name, node}: https://github.com/mbta/ride_along/blob/1d393329af28c00f080d37b730b1ad725e70a59d/lib/ride_along/rider_notifier.ex#L60

server = Keyword.get(options, :server, default_name())
for node <- Node.list() do
  GenServer.cast({server, node}, {:detour_activated_notification, notification_id})
end

Copy link
Member Author

Choose a reason for hiding this comment

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

Awesome, that works!
https://github.com/mbta/skate/compare/c9cf2debf1e309c4140e4b43753b2d8b26356a97..37026f15ff15bba582f0b85b6ad6e158bba2142d

If you have any thoughts on how to automatically test this, let me know?
I was looking at https://elixirschool.com/en/lessons/advanced/otp_distribution#conditionally-excluding-tests-with-tags-11 but that didn't mention anything about automatically setting up a second test instance, and when I tried to do so, it seemed like I'd have to run a second real instance of Skate for the tests to run against.

Copy link
Member

Choose a reason for hiding this comment

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

I don't have any good answers for this, unfortunately. For RideAlong, I tested the code paths manually and tried to keep them simple.

If you don't have something already, you could test calling the cast and making sure is has the right effect?

Copy link
Member Author

Choose a reason for hiding this comment

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

If you have any thoughts on how to automatically test this, let me know?

I don't have any good answers for this, unfortunately. For RideAlong, I tested the code paths manually and tried to keep them simple.

This is what I've been doing locally

PORT=4001 iex \
	--sname 1@localhost \
	--cookie test \
	-S mix phx.server
iex \
	--sname 2@localhost \
	--cookie test \
	-S mix phx.server

And then run this on 2@localhost shell

Node.connect(:"1@localhost")

(which means I've not been able to test DNSCluster, because it gets mad when I don't run it in release mode, as well as I don't think I can put a socket address (IP + Port) into what would be returned from DNS for localhost)

extra

or of course the corresponding call for the other server

Node.connect(:"2@localhost")

And then I open a browser window to both servers and create and activate a detour and confirm that the other browser window on the other server.

lib/skate/application.ex Outdated Show resolved Hide resolved
@firestack firestack force-pushed the kf/asn/dn/distributed-notifications branch 2 times, most recently from c9cf2de to 37026f1 Compare October 2, 2024 18:40
options \\ []
)
when not is_nil(notification_id) do
server = Keyword.get(options, :server, default_name())
Copy link
Member Author

Choose a reason for hiding this comment

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

Oh hmmm, this will always return default_name() because options isn't passed from the caller on ln#111. We don't store the server name in the state, and we don't technically know the name of the server on the other node, we only know it because we haven't used a different name, but I think this would fail in tests?

Should this just be removed for now, or plumb the value through the original call to detour_activated or seomthing else?

I had originally thought I needed a "public" "caller function" (Something that calls GenServer.cast like detour_activated, and I then realized I didn't), so this is technically leftover code.

Copy link
Member

Choose a reason for hiding this comment

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

It needs to know the name of the server somehow, but there are bunch of ways:

  • require a static name
  • store the name in app config
  • store the name in the GenServer state

Copy link
Member Author

Choose a reason for hiding this comment

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

Since ideally we'd move to using Phoenix Channel PubSub anyway, I'll put it in the app config, since then tests could change the value.

Copy link
Member Author

Choose a reason for hiding this comment

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

@firestack firestack force-pushed the kf/asn/dn/distributed-notifications branch 2 times, most recently from d4601dc to 4391763 Compare October 3, 2024 12:33
@paulswartz
Copy link
Member

Code looks good (modulo the formatting issue) but I think it'd be good to put it up in one of the dev environments as well to make sure it works before merging.

@firestack
Copy link
Member Author

Code looks good (modulo the formatting issue) but I think it'd be good to put it up in one of the dev environments as well to make sure it works before merging.

We don't currently have multiple instances in our dev envs, maybe it's time to change that with this change?

@firestack
Copy link
Member Author

firestack commented Oct 3, 2024

Checked dev-blue and confirmed no changes to the functionality of sending notifications, but I've not been able to test and confirm (in a deployment environment using DNSCluster) that multiple instances work.

Base automatically changed from kf/fix/split-steps to main October 8, 2024 11:44
@firestack firestack force-pushed the kf/asn/dn/distributed-notifications branch from 1264374 to ed0102b Compare October 8, 2024 12:46
To be able to syncronize multiple Skate instances in production, we need to setup
distributed Elixir.

Following the way https://github.com/mbta/ride_along did it, this uses `DNSCluster`
to find the other Skate instances, and if the variable is not present, it does nothing
so this is safe to deploy to production before the corrisponding devops PR.
…connected Skate instances

refactor: reuse `detour_activated_notification` cast for all detour notifications
Copy link
Collaborator

@hannahpurcell hannahpurcell left a comment

Choose a reason for hiding this comment

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

👍

@firestack firestack merged commit 105614d into kf/refactor/notification-getter Oct 8, 2024
34 checks passed
@firestack firestack deleted the kf/asn/dn/distributed-notifications branch October 8, 2024 20:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants