-
Notifications
You must be signed in to change notification settings - Fork 30
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
Calcul et sauvegarde de métadonnées pour les ressources GBFS #1905
Conversation
36b5b3d
to
a8dfb43
Compare
a8dfb43
to
1553a0e
Compare
7132187
to
32aeb07
Compare
setup do | ||
:verify_on_exit! | ||
# Do not use a mock for the GBFS Validator as we'll mock HTTP calls | ||
old_value = Application.fetch_env!(:transport, :gbfs_validator_impl) | ||
on_exit(fn -> Application.put_env(:transport, :gbfs_validator_impl, old_value) end) | ||
Application.put_env(:transport, :gbfs_validator_impl, Shared.Validation.GBFSValidator.HTTPClient) | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similaire aux tests utilisant le "page cache" dans l'app GBFS
end | ||
|
||
@spec compute_feed_metadata(Resource.t()) :: map() | ||
def compute_feed_metadata(resource) do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
C'est cette fonction qui est testée avec attention
config/prod.exs
Outdated
@@ -20,6 +20,8 @@ config :transport, Transport.Scheduler, | |||
{"@daily", {Transport.DataChecker, :outdated_data, []}}, | |||
# Set inactive data | |||
{"@daily", {Transport.DataChecker, :inactive_data, []}}, | |||
# Compute metadata for GBFS resources | |||
{"@daily", {Transport.GBFSMetadata, :set_gbfs_feeds_metadata, []}}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Un avis sur la fréquence et l'enchainement par rapport aux autres jobs ?
Actuellement ça finit en moins de 30 secondes car ça analyse 30 feeds
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pour commencer une fois par nuit ça me paraît bien comme tu as mis là !
Après une fois qu'on sera sur du job récurrent, on pourra peut-être accélérer et voir comment ça gère.
Resource | ||
|> join(:inner, [r], d in Dataset, on: r.dataset_id == d.id) | ||
|> where([_r, d], d.type == "bike-scooter-sharing" and d.is_active) | ||
|> where([r, _d], like(r.url, "%gbfs.json") or r.format == "gbfs") | ||
|> where([r, _d], not fragment("? ~ ?", r.url, "station|free_bike")) | ||
|> Repo.all() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reprend la requête SQL ici #1891 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Je vais proposer de petits refactorings sur les tests, et ajouter un peu de doc, mais ça semble good !
@@ -8,6 +8,7 @@ defmodule Shared.Validation.GBFSValidator do | |||
A structure holding validation results for a GBFS feed | |||
""" | |||
@enforce_keys [:has_errors, :errors_count, :version_detected, :version_validated] | |||
@derive Jason.Encoder |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ttl: ttl(json) | ||
} | ||
else | ||
e -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dans le futur, peut-être qu'on gagnera à mettre de la télémétrie ici (et/ou à retourner une erreur à l'appelant)
iex> Transport.GBFSMetadata.has_cors?(%HTTPoison.Response{headers: [{"Access-Control-Allow-Origin", "*"}]}) | ||
true | ||
""" | ||
def has_cors?(%HTTPoison.Response{} = response) do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Toute cette partie pourra peut-être être bougée dans le futur vers un module non spécifique au GBFS, si on retrouve l'usage ailleurs.
The previous use was just an atom expression, evaluated but not leading to ExUnit callback call.
end | ||
end | ||
|
||
defp types(%{"data" => _data} = payload) do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dans un style un peu plus fonctionnel, je suggère :
defp types(%{"data" => _data} = payload) do | |
defp types(%{"data" => _data} = payload) do | |
result = | |
[] | |
|> maybe_add_type("free_floating", has_feed?(payload, "free_bike_status")) | |
|> maybe_add_type("stations", has_feed?(payload, "station_information")) | |
if Enum.empty?(result) do | |
Logger.error("Cannot detect GBFS types for feed #{inspect(payload)}") | |
nil | |
else | |
result | |
end | |
end | |
def maybe_add_type(result, tag, condition) do | |
if condition, do: result ++ [tag], else: result | |
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(à vérifier!)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Beau boulot !
J'ai fait des modifications liées à des éléments simples (simplification d'un test, correction d'un bug sur l'usage de Mox, etc), et fait une proposition de refactoring.
Par ailleurs plusieurs remarques de "haut niveau" (qui n'appellent pas forcément à modification, je te laisse juge, ou à dispo pour en discuter comme tu veux) :
Sérialisation / désérialisation
Il faudra faire attention au fait qu'une séquence sérialisation + désérialisation comme suit (dont je me suis servi pour regarder un peu le résultat dans IEx sans aller dans la base de données) ne redonne pas les mêmes éléments:
Transport.GBFSMetadata.gbfs_feeds_query()
|> DB.Repo.all()
|> Enum.take(1)
|> Enum.each(fn(resource) ->
Transport.GBFSMetadata.compute_feed_metadata(resource)
|> IO.inspect(IEx.inspect_opts())
|> Jason.encode!()
|> Jason.decode!()
|> IO.inspect(IEx.inspect_opts())
end)
%{
feeds: ["system_information", "station_information", "station_status"],
has_cors: false,
is_cors_allowed: false,
languages: ["en"],
system_details: %{name: "Vélocéo Vannes", timezone: "Europe/Paris"},
ttl: 60,
types: ["stations"],
validation: %Shared.Validation.GBFSValidator.Summary{
errors_count: 0,
has_errors: false,
version_detected: "1.0",
version_validated: "1.0"
},
versions: ["1.0"]
}
%{
"feeds" => ["system_information", "station_information", "station_status"],
"has_cors" => false,
"is_cors_allowed" => false,
"languages" => ["en"],
"system_details" => %{
"name" => "Vélocéo Vannes",
"timezone" => "Europe/Paris"
},
"ttl" => 60,
"types" => ["stations"],
"validation" => %{
"errors_count" => 0,
"has_errors" => false,
"version_detected" => "1.0",
"version_validated" => "1.0"
},
"versions" => ["1.0"]
}
En particulier le typage sur %Shared.Validation.GBFSValidator.Summary
disparaît.
C'est sans impact a priori là, mais à garder en tête si on utilise @derive Jason.Encoder
davantage.
Impact des méthodes privées defp
sur la complexité du test
Je pense qu'on pourrait avoir un test un peu "intégration" avec les stubs, et pour le reste tester plus unitairement chaque méthode (en la passant de defp
à def
), et que ça pourrait donner (à vérifier, c'est juste une intuition) des tests plus simples à appréhender.
(J'ai aussi adapté le code en provenance de |
@thbar Merci de ta relecture attentive et des tests localement ! Et des améliorations effectuées :) J'avais remarqué la différence de désérialisation/sérialisation où l'on perd la structure quand on récupère un objet depuis la BD. C'est facheux, mais je pense que c'est partout comme ça dans le projet étant donné qu'on indique juste que C'est vrai que je trouve que j'ai plus souvent à des |
Implémentation de #1852, utilise #1902
Cette PR ajoute une tâche quotidienne en charge de calculer et de stocker des métadonnées pour les ressources GBFS. Elle identifie les ressources GBFS, calcule des métadonnées (dont la validité du flux) et enregisre ceci dans les métadonnées de chaque ressource.
Un exemple de métadonnées