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

Add ability to mark instances as absent #1731

Merged
merged 14 commits into from
Aug 30, 2023
Merged

Add ability to mark instances as absent #1731

merged 14 commits into from
Aug 30, 2023

Conversation

jamie-suse
Copy link
Contributor

Description

When an instance is no longer responding, the corresponding MarkDatabaseInstanceAbsent/MarkApplicationInstanceAbsent command is dispatched (instead of Deregister*Instance). This even then applies an absent marker on the corresponding read/write models.

When an instance is registered, the absent field should be cleared.

How was this tested?

Updated unit tests to suit behaviour.

@jamie-suse jamie-suse added the elixir Pull requests that update Elixir code label Aug 22, 2023
@jamie-suse jamie-suse marked this pull request as draft August 22, 2023 13:54
Copy link
Contributor

@arbulu89 arbulu89 left a comment

Choose a reason for hiding this comment

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

@jamie-suse Looking better.
Some work still to be done yet hehe

@@ -0,0 +1,15 @@
defmodule Trento.Domain.Commands.MarkApplicationInstanceAbsent do
@moduledoc """
Mark an application instance as absent from the monitoring system.
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't really like this from the monitoring system. It is kind of implicit, isn't it?

@@ -17,5 +17,6 @@ defmodule Trento.Domain.SapSystem.Instance do
field :health, Ecto.Enum, values: Health.values()
field :system_replication, :string
field :system_replication_status, :string
field :absent_at, :utc_datetime_usec, default: nil
Copy link
Contributor

Choose a reason for hiding this comment

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

nil is the default value by default XD
You don't need to add it

lib/trento/domain/sap_system/sap_system.ex Show resolved Hide resolved
},
%RegisterDatabaseInstance{sap_system_id: sap_system_id}
)
when not is_nil(absent_at) do
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we maybe revert the logic to use a better pattern matching:

defp maybe_emit_database_instance_marked_present_event(
    %Instance{absent_at: nil}, %RegisterDatabaseInstance{}), do: nil

defp maybe_emit_database_instance_marked_present_event(
    %Instance{}, %RegisterDatabaseInstance{sap_system_id: sap_system_id, ....} do
    
    %DatabaseInstanceMarkedPresent{
          instance_number: instance_number,
          host_id: host_id,
          sap_system_id: sap_system_id
    }
end

The same goes for the application part.
Besides that, have a look on where this function should go checking the order of usage please.
I didn't have a proper look myself

lib/trento/domain/sap_system/sap_system.ex Show resolved Hide resolved
absent_at: absent_at
}
) do
%DatabaseInstanceMarkedAbsent{
Copy link
Contributor

Choose a reason for hiding this comment

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

Here we need to check if the instance was already absent.
We don't want to emit the event if it was already that way.
I guess simply get the instance and with a case check if the current value of absent. You don't need a new maybe function. Just do it here.

The same for the app

application: %Application{instances: instances},
deregistered_at: deregistered_at
} = sap_system,
%RegisterApplicationInstance{host_id: host_id, instance_number: instance_number} = command
Copy link
Contributor

Choose a reason for hiding this comment

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

I wouldn't rename this to command. It was ok as instance

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I thought to rename it as I need to use instance = get_instance(...) further down

sap_system
|> Multi.new()
|> Multi.execute(fn _ ->
maybe_emit_application_instance_marked_present_event(instance, command)
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's put this after the maybe_emit_application_instance_registered_or_moved_event event.
Besides that, and to follow with the already existing logic, I would pass sap_system/instance to the function, and run the get_instance within that one.
It looks cleaner and you reduce a duplicated code a bit (as you do it twice now)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was trying to make this in-line with the existing logic in execute(%SapSystem{}, %RegisterDatabaseInstance{}). But I've changed it 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Referring to the logic seen here:

@jamie-suse jamie-suse added the env Create an ephimeral environment for the pr branch label Aug 23, 2023
) do
%Instance{absent_at: instance_absent_at} = get_instance(instances, host_id, instance_number)

case instance_absent_at do
Copy link
Contributor

@arbulu89 arbulu89 Aug 24, 2023

Choose a reason for hiding this comment

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

case get_instance(instances, host_id, instance_number) do
    %Instance{absent_at: nil} ->
        %DatabaseInstanceMarkedAbsent{
            instance_number: instance_number,
            host_id: host_id,
            sap_system_id: sap_system_id,
            absent_at: absent_at
        }

    _ ->
        nil
end

@jamie-suse
Copy link
Contributor Author

FYI I had to rebase, so I squashed most commits down

@jamie-suse jamie-suse marked this pull request as ready for review August 29, 2023 13:21
Copy link
Contributor

@arbulu89 arbulu89 left a comment

Choose a reason for hiding this comment

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

Okey! Much better!
I think we need to work a bit more in the tests.
I would split the tests in smaller pieces and separate the databases and application flows, after all they have a totally independent flow

lib/trento/domain/sap_system/sap_system.ex Show resolved Hide resolved
@@ -4202,6 +4208,361 @@ defmodule Trento.SapSystemTest do
end
end

describe "delta deregistration" do
Copy link
Contributor

Choose a reason for hiding this comment

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

I wouldn't call this delta deregistration.
Maybe instance marked absent/present or similar?

@@ -4202,6 +4208,361 @@ defmodule Trento.SapSystemTest do
end
end

describe "delta deregistration" do
test "newly registered instances should be marked as present" do
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need this 1st test?
We have plenty of tests where we have a regular registration. We could add the absent_at pattern matching in any of them.

Copy link
Contributor

Choose a reason for hiding this comment

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

If you still want to keep it, i think we should still split the database and application parts.
But the test must be fixed in any case.
The database_instance_registered must not go in the initial events, as this is the event which triggers the change, so I would suggest to use the command in the 2nd param of assert_events_and_state

)
end

test "absent instances receiving 'mark as absent' command should mark as absent" do
Copy link
Contributor

Choose a reason for hiding this comment

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

I would put this test before the others.
The tests can tell the story of the flow as well, so we would set to absent before setting it back to present, right?

)
end

test "absent instances receiving 'mark as absent' command should mark as absent" do
Copy link
Contributor

Choose a reason for hiding this comment

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

I would rename this to should mark as absent a previously registered instance

Enum.map(
instances,
fn instance ->
if instance.instance_number == instance_number and instance.host_id == host_id do
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we pattern match instead of this if ?

@@ -1199,4 +1385,17 @@ defmodule Trento.Domain.SapSystem do
false
end)
end

defp update_instance(instances, instance_number, host_id, key, value) do
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't really like this key/value thing.
Could we send the whole new update and use maybe Map.merge?
https://hexdocs.pm/elixir/1.12/Map.html#merge/2

Copy link
Contributor

@arbulu89 arbulu89 left a comment

Choose a reason for hiding this comment

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

Some tiny things.
Ready to merge after them


embeds_one :database, Database
embeds_one :application, Application
field(:sap_system_id, Ecto.UUID)
Copy link
Contributor

Choose a reason for hiding this comment

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

Formatting error. Remove parenthesis please

instances,
fn
%Instance{instance_number: ^instance_number, host_id: ^host_id} = instance ->
struct(instance, fields)
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe I would put Kernel.struct to exactly know the module. Up to you

@@ -4202,6 +4210,365 @@ defmodule Trento.SapSystemTest do
end
end

describe "instance marked absent/present" do
test "should mark as absent a previously registered database instance" do
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure if mixing 2 different flows is a good idea, as it "hides" them.
I'm talking about the scenario where you test here that an already marked instance is not re-marked.
No need for a change, the test is totally correct.
For the future

sap_system_id: sap_system_id,
sid: sid,
host_id: host_id,
instance_number: absent_app_instance_number,
Copy link
Contributor

Choose a reason for hiding this comment

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

This is not an app instance in reallity, as it is a MESSAGESERVER

)
end

test "receiving a 'register instance' command for an already-registered database instance sets instance as present if absent" do
Copy link
Contributor

Choose a reason for hiding this comment

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

I would rephrase this to:

should mark as present and already registered absent database instance

We use the should wording at the beginning of each test by default

],
fn state ->
assert %SapSystem{
database: %SapSystem.Database{
Copy link
Contributor

Choose a reason for hiding this comment

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

SapSystem.Database to Database (already aliased in top).
The same for Instance and Application in all tests

sap_system_id: sap_system_id,
host_id: host_id,
instance_number: absent_app_instance_number,
absent_at: DateTime.utc_now()
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't this absent_at be created by the factory?

@jamie-suse jamie-suse requested a review from arbulu89 August 30, 2023 09:26
Copy link
Contributor

@arbulu89 arbulu89 left a comment

Choose a reason for hiding this comment

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

Alright!
Green light from my side.
@rtorrero would you like to give a second look if I missed something?

@arbulu89 arbulu89 added the enhancement New feature or request label Aug 30, 2023
@jamie-suse jamie-suse added env Create an ephimeral environment for the pr branch and removed env Create an ephimeral environment for the pr branch labels Aug 30, 2023
@arbulu89 arbulu89 merged commit 8a4da21 into main Aug 30, 2023
@arbulu89 arbulu89 deleted the mark-absent branch August 30, 2023 14:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
elixir Pull requests that update Elixir code enhancement New feature or request env Create an ephimeral environment for the pr branch
Development

Successfully merging this pull request may close these issues.

3 participants