Closed thbar closed 2 years ago
Si je fais une query, je vois que le retour d'API fait 17 mégas. Certaines ressources prennent beaucoup de place en terme de JSON, et ça semble lié à l'output des validations qui est intégré directement. Je vais essayer de regrouper quelques stats.
Plutôt que jq
, j'ai utilisé un script Elixir et c'était drôlement plus pratique pour filtrer ça:
Mix.install([:jason])
"data.json"
|> File.read!()
|> Jason.decode!()
|> Enum.map(&(&1["resources"]))
|> List.flatten
|> Enum.map(fn(x) -> {x["datagouv_id"], x |> get_in(["metadata", "validation", "errors_count"]) } end)
|> Enum.filter(fn({_d, c}) -> c != nil && c > 10 end)
|> IO.inspect(IEx.inspect_opts)
Le retour est le suivant:
[
{"65988d54-1ba2-4ea5-86c8-2ba30162e211", 97441},
{"aba5743e-230f-49dd-8270-39efc5a72460", 6663},
{"8218f747-8c53-49d3-8470-24c0afef3dfb", 13594},
{"50625621-18bd-43cb-8fde-6b8c24bdabb3", 1000},
{"d732ee90-83df-4161-af71-9aa2cf23952e", 1576},
{"b11dffe1-dcf9-438e-99bb-23cca0a6761a", 20056},
{"9ca17d67-3ba3-410b-9e32-6ac7948c3e06", 27660},
{"ffbd75ac-8e9b-45c2-984d-97599d33d00d", 4441},
{"da69c1d8-68ff-4068-8e5a-b9bd201f8988", 32},
{"1da34e46-dca1-4ace-be79-41c1116c9530", 40},
{"cb26e169-b319-42fd-8d98-be61b94c27a6", 1074},
{"8ed8a6e7-0385-4a87-b0cc-15e4a24fcd26", 28},
{"4eb730eb-34e3-4456-a42c-75b36e7a6a55", 13},
{"a6a84a04-5c1d-4a5b-aa5d-a0734cdac810", 17336}
]
En googlant un peu, je vois que RangeError: Out of memory
est un message typiquement Javascript. Je pense que la payload est peut-être digérée côté client (si j'ai compris comment cette implémentation Swagger fonctionne), et que la taille pourrait bien être le point bloquant.
Ca pourrait également expliquer le souci d'erreur 500 côté Zapier dans le test réalisé par @NicolasBerthelot (17M c'est vraiment inhabituel pour une payload JSON d'API simple).
En affinant je vois que ces grosses payloads sont toutes liées à de la validation jsonschema:
Mix.install([:jason])
"data.json"
|> File.read!()
|> Jason.decode!()
|> Enum.map(&(&1["resources"]))
|> List.flatten
|> Enum.filter(fn(d) ->
c = get_in(d, ["metadata", "validation", "errors_count"])
c != nil && c > 10
end)
|> Enum.map(&(&1["metadata"]["validation"]["schema_type"]))
|> IO.inspect(IEx.inspect_opts)
["jsonschema", "jsonschema", "jsonschema", "tableschema", "jsonschema",
"jsonschema", "jsonschema", "jsonschema", "jsonschema", "jsonschema",
"jsonschema", "jsonschema", nil, "jsonschema"]
https://github.com/etalab/transport-site/issues/1850 aurait permis d'avoir un peu plus de précisions, donc un nouveau vote pour implémenter cet ajout de champs dans l'API.
Je crée un ticket séparé et clair pour indiquer qu'il faudra "trimmer" la payload par défaut.
Fixed by #2097
Je vous laisserai fermer cette issue une fois que vous aurez vérifié qu'il n'y a pas de problème à appeler l'API via un logiciel tiers/Swagger UI
Ca a bien fondu (5,5MB au lieu de 17MB) mais Swagger plante encore. Je vais partager un petit "breakdown" ici, je garde assigné.
Je suis à 3.1MB avec l'onglet "Network" de Chrome
J'ai pareil à présent en fait ; j'ai peut-être pretty printé au passage.
@AntoineAugusti ah non je pense que c'est peut-être que j'ai lancé la requête après le deploy, mais avant ton nettoyage ? Enfin bref. Je vais quand même analyser car ça reste trop gros pour Swagger.
Les choses que j'ai pu vérifier jusque là sont les suivantes:
J'ai lancé une première analyse avec https://www.debugbear.com/json-size-analyzer sur l'output de https://transport.data.gouv.fr/api/datasets
, et j'ai expandé un peu le résultat, ça donne ceci:
Voir https://github.com/open-api-spex/open_api_spex/issues/421, on est sur une version EOL (depuis peu) servie par un plug. J'ai regardé car j'essayais de comprendre si en mettant à jour, et avec le fix #2097, ça aurait pu suffire.
Avec la commande suivante:
docker pull swaggerapi/swagger-ui
docker run -p 80:8080 swaggerapi/swagger-ui
On peut ensuite saisir l'url de notre JSON Swagger dispo ici https://transport.data.gouv.fr/api/openapi.
J'obtiens les résultats suivants:
Notre API est trop verbeuse. Il faudra:
Le test sous Zapier est toujours non concluant ; je pense que 3 MB ça reste bien trop gros pour un retour d'API JSON "classique", il va falloir voir si on fait fondre davantage, quitte à ensuite permettre d'autres opérations.
J'ai une bonne piste en fait : on a 2 datasets qui sont des "baleines". Je vais partager mes analyses, mais ça devrait faire fondre pas mal le tout.
Après un peu de scripting, j'ai effectivement la preuve qu'on a 2 datasets qui sont très imposants, et c'est lié aux ressources communautaires:
Voilà l'analyse: j'ai utilisé l'API pour déterminer quels sont les datasets dont la partie d'API, ré-encodée en JSON, est au dessus de 20k:
[
%{
id: "5eab66a565c27001ac5f11ed",
page_url: "https://transport.data.gouv.fr/datasets/zfe-zone-a-faibles-emissions",
reencoded_byte_size: 21693
},
%{
id: "5b4f2f52c751df4ea419aef3",
page_url: "https://transport.data.gouv.fr/datasets/base-de-donnees-multimodale-transports-publics-en-bretagne-mobibreizh",
reencoded_byte_size: 23720
},
%{
id: "5f3c6c44cadb68fa4c58be26",
page_url: "https://transport.data.gouv.fr/datasets/arrets-horaires-et-parcours-theoriques-gtfs-des-differents-reseaux-de-transport-membres-du-synd3-1",
reencoded_byte_size: 988827
},
%{
id: "5b3b3de988ee38708ada1789",
page_url: "https://transport.data.gouv.fr/datasets/reseaux-de-transports-en-commun-de-la-metropole-daix-marseille-provence-et-des-bouches-du-rhone",
reencoded_byte_size: 714734
}
]
Le script est le suivant:
Mix.install([
:jason, :req
])
defmodule FileCache do
def fetch!(filename, cb) do
unless File.exists?(filename), do: File.write!(filename, cb.())
File.read!(filename)
end
end
datasets = FileCache.fetch!("data.json", fn ->
%{status: 200, body: body} = Req.build(:get, "https://transport.data.gouv.fr/api/datasets") |> Req.run!()
body
end)
datasets
|> Jason.decode!()
|> Enum.map(fn(dataset) ->
%{
id: dataset["id"],
# dataset: dataset,
page_url: dataset["page_url"],
reencoded_byte_size: dataset |> Jason.encode!() |> byte_size()
}
end)
|> Enum.filter(fn(d) -> d[:reencoded_byte_size] > 20_000 end)
|> Enum.map(fn(dataset) ->
dataset
end)
|> IO.inspect(IEx.inspect_opts)
Il semblerait que #2098 n'aie pas suffi à nettoyer pour les deux gros datasets, car j'ai le même résultat:
[
%{
id: "5eab66a565c27001ac5f11ed",
page_url: "https://transport.data.gouv.fr/datasets/zfe-zone-a-faibles-emissions",
reencoded_byte_size: 21693
},
%{
id: "5f3c6c44cadb68fa4c58be26",
page_url: "https://transport.data.gouv.fr/datasets/arrets-horaires-et-parcours-theoriques-gtfs-des-differents-reseaux-de-transport-membres-du-synd3-1",
reencoded_byte_size: 988827
},
%{
id: "5b3b3de988ee38708ada1789",
page_url: "https://transport.data.gouv.fr/datasets/reseaux-de-transports-en-commun-de-la-metropole-daix-marseille-provence-et-des-bouches-du-rhone",
reencoded_byte_size: 714734
}
]
Il va falloir enquêter.
Je me suis appuyé sur l'API qui retourne la donnée d'un dataset donné, pour afficher cela plus facilement:
Si je pipe ça dans jq
, j'ai:
❯ curl --silent https://transport.data.gouv.fr/api/datasets/5f3c6c44cadb68fa4c58be26 | jq ".community_resources | length"
1418
❯ curl --silent https://transport.data.gouv.fr/api/datasets/5b3b3de988ee38708ada1789 | jq ".community_resources | length"
938
Donc sauf erreur on a encore 1418+938 ressources communautaires à purger ici.
Si je vais sur la page data.gouv.fr du premier : https://www.data.gouv.fr/fr/datasets/arrets-horaires-et-parcours-theoriques-gtfs-des-differents-reseaux-de-transport-membres-du-synd3-1/#community-resources Il en reste 13.
Et le 2ème, il en reste 0. https://www.data.gouv.fr/fr/datasets/reseaux-de-transports-en-commun-de-la-metropole-daix-marseille-provence-et-des-bouches-du-rhone/#community-resources
C'est plus un problème lors de l'import data.gouv => transport visiblement.
Effectivement, j'ai essayé d'importer à la main, et ça échoue, probablement à cause de la taille de la transaction. Je vais supprimer les ressources communautaires à la main.
le dataset 146 :
et le 506 :
Super merci @fchabouis d'avoir été voir de l'autre côté !
Les payloads sont bien allégées de leurs ressources communautaires :
❯ curl --silent https://transport.data.gouv.fr/api/datasets/5f3c6c44cadb68fa4c58be26 | jq ".community_resources | length"
13
❯ curl --silent https://transport.data.gouv.fr/api/datasets/5b3b3de988ee38708ada1789 | jq ".community_resources | length"
0
Par contre il reste un souci de taille malgré tout, je regarde de plus près.
Les datasets ont fondu, les plus gros sont à présent:
%{
id: "5eab66a565c27001ac5f11ed",
page_url: "https://transport.data.gouv.fr/datasets/zfe-zone-a-faibles-emissions",
reencoded_byte_size: 21693
},
%{
id: "5f3c6c44cadb68fa4c58be26",
page_url: "https://transport.data.gouv.fr/datasets/arrets-horaires-et-parcours-theoriques-gtfs-des-differents-reseaux-de-transport-membres-du-synd3-1",
reencoded_byte_size: 22778
}
]
On est passé de 3.1 MB à 900k à présent (en partant de 17 MB à l'origine):
$ curl -I https://transport.data.gouv.fr/api/datasets | grep content-length
content-length: 923898
Safari met super longtemps (plusieurs minutes) à digérer l'appel Swagger pour https://transport.data.gouv.fr/swaggerui#/datasets/API.DatasetController.datasets, mais à présent ça fonctionne.
Idem de l'autre côté avec Chrome.
Je vais avoir avec @NicolasBerthelot si ça suffit pour avancer dans Zapier, puis je clôturerai ici.
Ma conclusion est quand même qu'il faudrait alléger le retour principal de l'API, avec moins de choses dedans par défaut, et probablement une forme de pagination (même si pour les outils comme Zapier après ça complique un peu la donne), si on ne peut pas alléger, car en l'état pas mal d'outils vont avoir un peu de mal !
J'ai créé un ticket spécifique (#2101) pour le problème de Zapier, dont @NicolasBerthelot a confirmé qu'il continuait à se produire malgré les optimisations (mais qui ne sont pas perdues, elles étaient nécessaires je pense).
Si je vais ici:
https://transport.data.gouv.fr/swaggerui#/datasets/API.DatasetController.datasets
et que je clique sur "execute", j'obtiens :
Le site n'a pas l'air d'être tombé pour autant.