From 2e45f8aca02d2d4f8007881386a9e9aec3b666db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Wed, 18 Sep 2024 16:10:35 +0200 Subject: [PATCH] Deal with clock drifts and use DateTime UTC for server data (#2787) --- lib/livebook/hubs/team_client.ex | 2 +- lib/livebook/teams/app_deployment.ex | 5 ++-- lib/livebook/utils/time.ex | 23 ++++++++++++------- lib/livebook_web/helpers/html_helpers.ex | 2 +- test/livebook_teams/hubs/team_client_test.exs | 4 ++-- test/support/factory.ex | 6 ++--- 6 files changed, 24 insertions(+), 18 deletions(-) diff --git a/lib/livebook/hubs/team_client.ex b/lib/livebook/hubs/team_client.ex index 275d83d2d..23467245d 100644 --- a/lib/livebook/hubs/team_client.ex +++ b/lib/livebook/hubs/team_client.ex @@ -469,7 +469,7 @@ defmodule Livebook.Hubs.TeamClient do deployment_group_id: app_deployment.deployment_group_id, file: nil, deployed_by: app_deployment.deployed_by, - deployed_at: NaiveDateTime.from_gregorian_seconds(app_deployment.deployed_at) + deployed_at: DateTime.from_gregorian_seconds(app_deployment.deployed_at) } end diff --git a/lib/livebook/teams/app_deployment.ex b/lib/livebook/teams/app_deployment.ex index e48459c03..9b4f72942 100644 --- a/lib/livebook/teams/app_deployment.ex +++ b/lib/livebook/teams/app_deployment.ex @@ -16,7 +16,7 @@ defmodule Livebook.Teams.AppDeployment do deployment_group_id: String.t() | nil, file: binary() | nil, deployed_by: String.t() | nil, - deployed_at: NaiveDateTime.t() | nil + deployed_at: DateTime.t() | nil } @access_types Livebook.Notebook.AppSettings.access_types() @@ -33,8 +33,7 @@ defmodule Livebook.Teams.AppDeployment do field :deployment_group_id, :string field :file, :string field :deployed_by, :string - - timestamps(updated_at: nil, inserted_at: :deployed_at) + field :deployed_at, :utc_datetime end @doc """ diff --git a/lib/livebook/utils/time.ex b/lib/livebook/utils/time.ex index 68e572bc8..c225beb04 100644 --- a/lib/livebook/utils/time.ex +++ b/lib/livebook/utils/time.ex @@ -3,16 +3,18 @@ defmodule Livebook.Utils.Time do @doc """ Formats the given point in time relatively to present. + + ## Examples + + To deal with clock-drifts when receiving timestamps from the server, we accept future times: + + iex> Livebook.Utils.Time.time_ago_in_words(~N[2100-06-20 18:15:00]) + "less than 5 seconds" + """ @spec time_ago_in_words(NaiveDateTime.t()) :: String.t() def time_ago_in_words(naive_date_time) when is_struct(naive_date_time, NaiveDateTime) do - now = NaiveDateTime.utc_now() - - if NaiveDateTime.compare(naive_date_time, now) == :gt do - raise ArgumentError, "expected a datetime in the past, got: #{inspect(naive_date_time)}" - end - - distance_of_time_in_words(naive_date_time, now) + distance_of_time_in_words(naive_date_time, NaiveDateTime.utc_now()) end @doc """ @@ -75,6 +77,11 @@ defmodule Livebook.Utils.Time do iex> Livebook.Utils.Time.distance_of_time_in_words(~N[2020-06-20 18:15:00], ~N[2021-08-22 18:15:00]) "about 14 months" + To deal with clock-drifts when receiving timestamps from another machine, we accept future times: + + iex> Livebook.Utils.Time.distance_of_time_in_words(~N[2020-06-20 18:15:06], ~N[2020-06-20 18:15:04]) + "less than 5 seconds" + """ @spec distance_of_time_in_words(NaiveDateTime.t(), NaiveDateTime.t()) :: String.t() def distance_of_time_in_words(from_ndt, to_ndt) @@ -92,7 +99,7 @@ defmodule Livebook.Utils.Time do defp maybe_convert_to_minutes(duration), do: duration - defp duration_in_words({:seconds, seconds}) when seconds in 0..4 do + defp duration_in_words({:seconds, seconds}) when seconds <= 4 do "less than 5 seconds" end diff --git a/lib/livebook_web/helpers/html_helpers.ex b/lib/livebook_web/helpers/html_helpers.ex index 46df935f0..0071ae5ab 100644 --- a/lib/livebook_web/helpers/html_helpers.ex +++ b/lib/livebook_web/helpers/html_helpers.ex @@ -73,7 +73,7 @@ defmodule LivebookWeb.HTMLHelpers do Formats the given UTC datetime relatively to present. """ @spec format_datetime_relatively(DateTime.t() | NaiveDateTime.t()) :: String.t() - def format_datetime_relatively(%DateTime{} = date) do + def format_datetime_relatively(%DateTime{time_zone: "Etc/UTC"} = date) do date |> DateTime.to_naive() |> Livebook.Utils.Time.time_ago_in_words() end diff --git a/test/livebook_teams/hubs/team_client_test.exs b/test/livebook_teams/hubs/team_client_test.exs index 6d09b6ad1..75604329e 100644 --- a/test/livebook_teams/hubs/team_client_test.exs +++ b/test/livebook_teams/hubs/team_client_test.exs @@ -663,10 +663,10 @@ defmodule Livebook.Hubs.TeamClientTest do version: Livebook.Utils.random_id(), file: nil, deployed_by: teams_app_deployment.app_revision.created_by.name, - deployed_at: teams_app_deployment.updated_at + deployed_at: DateTime.from_naive!(teams_app_deployment.updated_at, "Etc/UTC") } - {seconds, 0} = NaiveDateTime.to_gregorian_seconds(app_deployment.deployed_at) + {seconds, 0} = DateTime.to_gregorian_seconds(app_deployment.deployed_at) livebook_proto_app_deployment = %LivebookProto.AppDeployment{ diff --git a/test/support/factory.ex b/test/support/factory.ex index b1766dfd4..b34adcc70 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -106,10 +106,10 @@ defmodule Livebook.Factory do shasum = Base.encode16(md5_hash, case: :lower) deployed_at = - NaiveDateTime.utc_now() - |> NaiveDateTime.truncate(:second) + DateTime.utc_now() + |> DateTime.truncate(:second) - {seconds, 0} = NaiveDateTime.to_gregorian_seconds(deployed_at) + {seconds, 0} = DateTime.to_gregorian_seconds(deployed_at) %Livebook.Teams.AppDeployment{ id: "1",