{"id":1611,"date":"2023-03-06T12:37:50","date_gmt":"2023-03-06T11:37:50","guid":{"rendered":"https:\/\/www.loicmathieu.fr\/wordpress\/?p=1611"},"modified":"2023-03-06T17:54:30","modified_gmt":"2023-03-06T16:54:30","slug":"introduction-a-kestra","status":"publish","type":"post","link":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/informatique\/introduction-a-kestra\/","title":{"rendered":"Introduction \u00e0 Kestra"},"content":{"rendered":"<p>Kestra est un orchestrateur et scheduler de donn\u00e9e open source. Avec Kestra, les workflows de donn\u00e9es, appel\u00e9s flows, utilisent le format YAML et sont ex\u00e9cut\u00e9s par son moteur via un appel API, l&rsquo;interface utilisateur, ou un trigger (webhook, schedule, SQL query, Pub\/Sub message, \u2026).<\/p>\n<p>Les notions importantes de Kestra sont :<\/p>\n<ul><li>Le <strong>flow<\/strong> : qui d\u00e9crit la mani\u00e8re dont la donn\u00e9e sera orchestr\u00e9e (le workflow donc). C&rsquo;est une suite de <strong>tasks<\/strong>.<\/li>\n\n<li>La <strong>task<\/strong> : une \u00e9tape du <strong>flow<\/strong> qui va permettre de r\u00e9aliser une action sur une ou plusieurs donn\u00e9es entrantes, les <strong>inputs<\/strong>, puis de g\u00e9n\u00e9rer z\u00e9ro ou une donn\u00e9e en sortie, l&rsquo;<strong>output<\/strong>.<\/li>\n\n<li>L&rsquo;<strong>execution<\/strong> : qui est une instance de <strong>flow<\/strong> suite \u00e0 un d\u00e9clenchement.<\/li>\n\n<li>Le <strong>trigger<\/strong> : qui d\u00e9finie la mani\u00e8re dont un <strong>flow<\/strong> peut \u00eatre d\u00e9clench\u00e9.<\/li>\n<\/ul>\n<p>Nous allons voir ces notions en pratique dans la suite de l&rsquo;article.<\/p>\n<p>Pour lancer Kestra en local, le plus simple est d&rsquo;utiliser le fichier <a href=\"https:\/\/github.com\/kestra-io\/kestra\/blob\/develop\/docker-compose.yml\" rel=\"noopener nofollow\" target=\"_blank\">Docker compose fournit<\/a>, puis de le lancer via <code>docker compose up<\/code>.<\/p>\n<p>Ce Docker compose va lancer Kestra en mode <strong>standalone<\/strong> (tous les composants en un seul processus) avec une base de donn\u00e9es PostgreSQL comme queue et repository (pour le stockage et l&rsquo;ex\u00e9cution des flows) et un storage local (pour le stockage des donn\u00e9es des flows).<\/p>\n<p>Kestra est compos\u00e9 de plusieurs composants qui communiquent ensemble via des queues et stockent les informations des flows via des repositories, ces queues et repositories peuvent \u00eatre impl\u00e9ment\u00e9es de diff\u00e9rentes mani\u00e8res (memory, JDBC, Kafka, Elasticsearch). Je ne vais pas entrer en d\u00e9tail dans l&rsquo;architecture de Kestra aujourd&rsquo;hui, mais pour les plus curieux vous pouvez vous r\u00e9f\u00e9rer \u00e0 la <a href=\"https:\/\/kestra.io\/docs\/architecture\/\" target=\"_blank\" rel=\"noopener\">documentation d&rsquo;architecture<\/a> de Kestra.<\/p>\n<p>Une fois Kestra d\u00e9marr\u00e9, une interface graphique sera disponible sur le port 8080 : <a href=\"http:\/\/localhost:8080\" rel=\"noopener nofollow\" target=\"_blank\"><a href=\"http:\/\/localhost:8080\">http:\/\/localhost:8080<\/a><\/a>, c&rsquo;est via cette interface que nous allons faire tous les exemples de cet article.<\/p>\n<p>Au premier lancement, un Guided Tour vous sera propos\u00e9, vous pouvez le suivre ou le passer pour pouvoir suivre les exemples de cet article.<\/p>\n<h2>Mon premier flow<\/h2>\n<p>Pour cr\u00e9er un flow, allez dans le menu <strong>Flows<\/strong> puis cliquez sur le bouton <strong>Create<\/strong> en bas \u00e0 droite. Vous voici maintenant avec un textarea dans lequel vous allez pouvoir entrer le descriptif YAML du flow.<\/p>\n<pre lang=\"yaml\">\nid: hello-world\nnamespace: fr.loicmathieu.example\n\ntasks:\n  - id: hello\n    type: io.kestra.core.tasks.debugs.Echo\n    format: \"Hello World\"\n<\/pre>\n<p>Un flow a :<\/p>\n<ul><li>Une propri\u00e9t\u00e9 <code>id<\/code> qui est son identifiant unique au sein d&rsquo;un namespace.<\/li>\n\n<li>Une propri\u00e9t\u00e9 <code>namespace<\/code>, un namespace est un espace de nommage pour les flux, les namespaces sont hierarchique comme les r\u00e9pertoires d&rsquo;un syst\u00e8me de fichier.<\/li>\n\n<li>Une propri\u00e9t\u00e9 <code>tasks<\/code> qui est la liste des t\u00e2ches \u00e0 r\u00e9aliser \u00e0 l&rsquo;ex\u00e9cution du flow.<\/li>\n<\/ul>\n<p>Ici, nous avons ajout\u00e9 une seule t\u00e2che qui a trois propri\u00e9t\u00e9s :<\/p>\n<ul><li>Une propri\u00e9t\u00e9 <code>id<\/code> qui est son identifiant unique au sein du flow.<\/li>\n\n<li>Une propri\u00e9t\u00e9 <code>type<\/code> qui est le nom de la classe qui repr\u00e9sente la t\u00e2che.<\/li>\n\n<li>Une propri\u00e9t\u00e9 <code>format<\/code>, c&rsquo;est une propri\u00e9t\u00e9 propre aux t\u00e2ches de type Echo qui d\u00e9finit le format du message \u00e0 logguer (une t\u00e2che de type Echo est comme la commande shell echo).<\/li>\n<\/ul>\n<p>Chaque t\u00e2che aura ses propres propri\u00e9t\u00e9s, elles sont document\u00e9es dans la documentation en ligne ainsi que dans la documentation int\u00e9gr\u00e9e \u00e0 l&rsquo;interface graphique de Kestra (Documentation -&gt; Plugins -&gt; puis s\u00e9lectionnez un plugin dans le menu de droite).<\/p>\n<p>Au sein de l&rsquo;\u00e9diteur, la description YAML du flow est valid\u00e9 et de l&rsquo;autocompl\u00e9tion est disponible pour le type et les propri\u00e9t\u00e9s des t\u00e2ches via CTRL+SPACE.<\/p>\n<p>Kestra se base sur un syst\u00e8me de plugins qui permet d&rsquo;ajouter des t\u00e2ches (mais aussi des triggers ou des conditions qu&rsquo;on verra plus tard). Par d\u00e9faut, il y a tr\u00e8s peu de plugins fournit dans Kestra mais l&rsquo;image Docker utilis\u00e9e dans le Docker compose est construite en ajoutant tous les plugins maintenus par l&rsquo;\u00e9quipe de d\u00e9veloppement de Kestra, leur documentation est ici : <a href=\"https:\/\/kestra.io\/plugins\/\" rel=\"noopener\" target=\"_blank\"><a href=\"https:\/\/kestra.io\/plugins\/\">https:\/\/kestra.io\/plugins\/<\/a><\/a>.<\/p>\n<p>Pour lancer ce premier flow, allez dans l&rsquo;onglet <strong>Executions<\/strong> puis cliquez sur le bouton <strong>New Execution<\/strong>.\nVous basculerez alors sur la vue Gantt de l&rsquo;ex\u00e9cution du flow qui est mise \u00e0 jour en temps r\u00e9elle avec le statut de l&rsquo;ex\u00e9cution.<\/p>\n<img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-01.png?resize=640%2C167&#038;ssl=1\" alt=\"\" width=\"640\" height=\"167\" class=\"alignnone size-large wp-image-1628\" srcset=\"https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-01.png?resize=1024%2C267&amp;ssl=1 1024w, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-01.png?resize=300%2C78&amp;ssl=1 300w, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-01.png?resize=768%2C200&amp;ssl=1 768w, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-01.png?resize=1536%2C400&amp;ssl=1 1536w, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-01.png?resize=604%2C157&amp;ssl=1 604w, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-01.png?w=1631&amp;ssl=1 1631w, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-01.png?w=1280&amp;ssl=1 1280w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/>\n<p>L&rsquo;onglet <strong>Logs<\/strong> permet de voir les logs de l&rsquo;ex\u00e9cution.<\/p>\n<img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-02.png?resize=640%2C169&#038;ssl=1\" alt=\"\" width=\"640\" height=\"169\" class=\"alignnone size-large wp-image-1629\" srcset=\"https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-02.png?resize=1024%2C270&amp;ssl=1 1024w, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-02.png?resize=300%2C79&amp;ssl=1 300w, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-02.png?resize=768%2C203&amp;ssl=1 768w, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-02.png?resize=1536%2C405&amp;ssl=1 1536w, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-02.png?resize=604%2C159&amp;ssl=1 604w, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-02.png?w=1591&amp;ssl=1 1591w, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-02.png?w=1280&amp;ssl=1 1280w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/>\n<p>On peut remarquer le log <code>Hello World<\/code> g\u00e9n\u00e9r\u00e9 par la t\u00e2che <strong>hello<\/strong>.<\/p>\n<p>Ajoutons maintenant un input nomm\u00e9 <strong>name<\/strong> \u00e0 notre flow pour lui donne le nom de la personne \u00e0 qui dire bonjour.\nPour cela, il faut \u00e9diter le flow en s\u00e9lectionnant le flow, soit via la navigation breadcrumb en haut ( Home \/ Flows \/ fr.loicmathieu.example.hello-world), soit en cliquant \u00e0 gauche sur <strong>Flows<\/strong> et en le s\u00e9lectionnant dans la liste ; puis aller dans l&rsquo;onglet <strong>Source<\/strong>.<\/p>\n<p>On peut passer des donn\u00e9es \u00e0 un flow via des inputs. Nous allons d\u00e9finir un input <strong>name<\/strong> de type <strong>STRING<\/strong>.<\/p>\n<pre lang=\"yaml\">\nid: hello-world\nnamespace: fr.loicmathieu.example\n\ninputs:\n  - type: STRING\n    name: name\n\ntasks:\n  - id: hello\n    type: io.kestra.core.tasks.debugs.Echo\n    format: \"Hello {{inputs.name}}\"\n<\/pre>\n<p>Quand on clique sur le boutton New Execution pour ex\u00e9cuter un flow, un formulaire nous demande de renseigner les inputs du flow.<\/p>\n<img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-03.png?resize=640%2C164&#038;ssl=1\" alt=\"\" width=\"640\" height=\"164\" class=\"alignnone size-large wp-image-1630\" srcset=\"https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-03.png?resize=1024%2C262&amp;ssl=1 1024w, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-03.png?resize=300%2C77&amp;ssl=1 300w, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-03.png?resize=768%2C197&amp;ssl=1 768w, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-03.png?resize=1536%2C394&amp;ssl=1 1536w, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-03.png?resize=604%2C155&amp;ssl=1 604w, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-03.png?w=1600&amp;ssl=1 1600w, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-03.png?w=1280&amp;ssl=1 1280w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/>\n<p>Apr\u00e8s avoir rentr\u00e9 une valeur pour le nom et ex\u00e9cut\u00e9 le flow, on peut constater que le log contient bien la valeur de l&rsquo;input.<\/p>\n<p><code>Hello {{inputs.name}}<\/code> est une expression qui utilise le moteur de templating Pebble qui va faire un rendu de ce qui est entre les moustaches <code>{{<\/code> et <code>}}<\/code>. Ici l&rsquo;expression Pebble va chercher la valeur de la variable <strong>inputs.name<\/strong> qui pointe vers l&rsquo;input de nom <strong>name<\/strong>.<\/p>\n<h2>Inputs et BigQuery<\/h2>\n<p>Dans cet exemple, le flow va prendre en entr\u00e9e (en input) un fichier CSV, le charger dans Google BigQuery, puis ex\u00e9cuter une requ\u00eate sur les donn\u00e9es charg\u00e9es et afficher dans les logs le r\u00e9sultat.<\/p>\n<p>J&rsquo;utilise ici BigQuery car c&rsquo;est plus simple que de d\u00e9marrer une base de donn\u00e9es, mais cela n\u00e9cessite un compte Google Cloud et un service account de configur\u00e9. Pour faire cela, il faut cr\u00e9er un <a href=\"https:\/\/cloud.google.com\/iam\/docs\/service-account-overview\" rel=\"noopener\" target=\"_blank\">service account<\/a> Google Cloud et le renseigner dans la propri\u00e9t\u00e9 <code>serviceAccount<\/code> de la t\u00e2che BigQuery. Pour \u00e9viter de coder en dure cette variable, il est possible d&rsquo;utiliser une variable d&rsquo;environement ou une variable globale au cluster, voir la documentation en ligne sur les <a href=\"https:\/\/kestra.io\/docs\/developer-guide\/variables\/\" rel=\"noopener\" target=\"_blank\">variables<\/a>.<\/p>\n<p>Sans plus tarder, la solution ; )<\/p>\n<pre lang=\"yaml\">\nid: beer\nnamespace: fr.loicmathieu.example\ndescription: A flow to handle my beers data\n\ninputs:\n  - type: FILE\n    description: Beers data\n    name: beers\n\ntasks:\n  - id: start-log\n    type: io.kestra.core.tasks.debugs.Echo\n    format: \"{{taskrun.startDate}} - {{task.id}} - Launching the flow\"\n  - id: load-beers\n    type: io.kestra.plugin.gcp.bigquery.Load\n    serviceAccount: \"\"\n    csvOptions:\n      fieldDelimiter: \",\"\n    destinationTable: beers.beers\n    format: CSV\n    from: \"{{inputs.beers}}\"\n  - id: query-beers\n    type: io.kestra.plugin.gcp.bigquery.Query\n    serviceAccount: \"\"\n    fetchOne: true\n    sql: |\n      SELECT count(*) as count FROM beers.beers\n  - id: end-log\n    type: io.kestra.core.tasks.debugs.Echo\n    format: \"{{taskrun.startDate}} - {{outputs['query-beers'].row.count}} beers loaded\"\n<\/pre>\n<p>J&rsquo;ai d\u00e9fini ici un input de type <code>FILE<\/code> nomm\u00e9 <strong>beers<\/strong>. Kestra va d\u00e9tecter le type de l&rsquo;input et g\u00e9n\u00e9rer le formulaire d&rsquo;ex\u00e9cution du flow correspondant. Cela permettra d&rsquo;uploader un fichier CSV contenant une liste de bi\u00e8re. Ce fichier sera stock\u00e9 dans le stockage interne de Kestra et disponible dans toutes les t\u00e2ches.<\/p>\n<p>La t\u00e2che <strong>load-beers<\/strong> de type <code>io.kestra.plugin.gcp.bigquery.Load<\/code> permet de charger un fichier CSV dans une table BigQuery. Le dataset BigQuery <strong>beers<\/strong> doit avoir \u00e9t\u00e9 cr\u00e9\u00e9 avant l&rsquo;ex\u00e9cution de cette t\u00e2che. La propri\u00e9t\u00e9 <strong>from<\/strong> prend un fichier du stockage interne (en r\u00e9alit\u00e9 l&rsquo;URI du fichier, celui-ci sera r\u00e9cup\u00e9r\u00e9 au dernier moment depuis le stockage interne). J&rsquo;utilise ici l&rsquo;expression Pebble <code>{{inputs.beers}}<\/code> pour r\u00e9cup\u00e9rer le fichier pass\u00e9 en input au flow.<\/p>\n<p>La t\u00e2che <strong>query-beers<\/strong> de type <code>io.kestra.plugin.gcp.bigquery.Query<\/code> permet d&rsquo;effectuer une requ\u00eate BigQuery. Il y a plusieurs mani\u00e8res de stocker le r\u00e9sultat de la requ\u00eate. Ici, j&rsquo;utilise la propri\u00e9t\u00e9 <code>fetchOne: true<\/code> qui configure la t\u00e2che pour r\u00e9cup\u00e9rer une seule ligne et mettre le r\u00e9sultat de la requ\u00eate en output de la t\u00e2che. Il est aussi possible de charger toutes les lignes (<code>fetch: true<\/code>), ou de stocker les r\u00e9sultats dans le stockage interne de Kestra (<code>store: true<\/code>) ce qui est conseill\u00e9 pour les requ\u00eates qui ram\u00e8nent beaucoup de lignes.<\/p>\n<p>La t\u00e2che <strong>end-log<\/strong> va \u00e9crire un log, nous l&rsquo;avons d\u00e9j\u00e0 vu pr\u00e9c\u00e9demment. Ici, nous voulons \u00e9crire dans les logs le nombre d&rsquo;enregistrements charg\u00e9s depuis la base de donn\u00e9es, nous allons donc r\u00e9cup\u00e9rer l&rsquo;output correspondant de la t\u00e2che <strong>query-beers<\/strong> via une expression Pebble : <code>{{outputs['query-beers'].row.count}}<\/code>.<\/p>\n<p>L&rsquo;expression <code>{{outputs['query-beers'].row.count}}<\/code> peut sembler intrigante :<\/p>\n<ul><li><code>outputs['query-beers']<\/code> : signifie l&rsquo;output de la t\u00e2che <strong>query-beers<\/strong>, nous avons jusqu&rsquo;\u00e0 pr\u00e9sent vu la notation point\u00e9e (.) pour acc\u00e9der aux outputs, mais quand celui-ci contenant un caract\u00e8re &lsquo;-&lsquo;, on est oblig\u00e9 d&rsquo;utiliser la notation subscript ([]) car &lsquo;-&lsquo; est un caract\u00e8re sp\u00e9cial pour Pebble.<\/li>\n\n<li><code>row<\/code> : est le nom de l&rsquo;attribut mis en output dans la t\u00e2che <strong>query-beers<\/strong>, une t\u00e2che peut avoir plusieurs attributs en outputs, se r\u00e9f\u00e9rer \u00e0 la documentation de la t\u00e2che pour leur liste.<\/li>\n\n<li><code>count<\/code> : est le nom de la colonne.<\/li>\n<\/ul>\n<h2>ForEach et format de fichier<\/h2>\n<p>Dans cet exemple, nous allons requ\u00eater les 10 pages Wikipedia les plus vues gr\u00e2ce au dataset public BigQuery <strong>wikipedia.pageviews_2023<\/strong> pour les langues fran\u00e7ais, anglais et allemand. Puis nous allons transformer le r\u00e9sultat en CSV.<\/p>\n<pre lang=\"yaml\">\nid: wikipedia-top-ten\nnamespace: fr.loicmathieu.example\ndescription: A flow that loads wikipedia top 10 FR pages each hour\n\ntasks:\n  - id: start-log\n    type: io.kestra.core.tasks.debugs.Echo\n    format: \"{{taskrun.startDate}} - {{task.id}} - Launching the flow\"\n  - id: for-each-countries\n    type: io.kestra.core.tasks.flows.EachSequential\n    tasks:\n      - id: query-top-ten\n        type: io.kestra.plugin.gcp.bigquery.Query\n        serviceAccount: \"\"\n        sql: |\n          SELECT DATETIME(datehour) as date, title, views \n          FROM `bigquery-public-data.wikipedia.pageviews_2023` \n          WHERE DATE(datehour) = current_date() and wiki = '{{taskrun.value}}' and title not in ('Cookie_(informatique)', 'Wikip\u00e9dia:Accueil_principal', 'Sp\u00e9cial:Recherche')\n          ORDER BY datehour desc, views desc\n          LIMIT 10\n        store: true\n      - id: write-csv\n        type: io.kestra.plugin.serdes.csv.CsvWriter\n        from: \"{{outputs['query-top-ten'][taskrun.value].uri}}\"\n    value: '[\"fr\", \"en\", \"de\"]'\n<\/pre>\n<p>La t\u00e2che <strong>for-each-countries<\/strong> de type <code>io.kestra.core.tasks.flows.EachSequential<\/code> permet de faire une boucle. Elle va r\u00e9aliser plusieurs fois la liste des t\u00e2ches enfant pour les valeurs pass\u00e9es dans sa propri\u00e9t\u00e9 <strong>value<\/strong> ; ici les langues fr, en et de.<\/p>\n<p>La t\u00e2che <strong>query-top-ten<\/strong> de type <code>io.kestra.plugin.gcp.bigquery.Query<\/code> va ex\u00e9cuter une requ\u00eate sur BigQuery qui sera stock\u00e9e dans le stockage interne de Kestra (<code>store: true<\/code>). Elle utilise l&rsquo;expression Pebble <code>{{taskrun.value}}<\/code> qui permet de r\u00e9cup\u00e9rer la valeur en cours de la boucle <code>EachSequential<\/code>.<\/p>\n<p>La t\u00e2che <strong>write-csv<\/strong> de type <code>io.kestra.plugin.serdes.csv.CsvWriter<\/code> va r\u00e9\u00e9crire le fichier stock\u00e9 par la t\u00e2che pr\u00e9c\u00e9dente au format CSV. Par d\u00e9faut, Kestra utilise le format de stockage objet Amazon Ion, cette t\u00e2che permet donc de passer du format Ion au format CSV. Elle utilise l&rsquo;expression Pebble <code>{{outputs['query-top-ten'][taskrun.value].uri}}<\/code> dont l&rsquo;attribut <code>[taskrun.value].uri<\/code> permet de r\u00e9cup\u00e9rer la valeur de l&rsquo;attribut <strong>uri<\/strong> pour l&rsquo;it\u00e9ration de boucle actuelle.<\/p>\n<p>Apr\u00e8s ex\u00e9cution du flow, vous pouvez aller dans l&rsquo;onglet <strong>Outputs<\/strong> pour acc\u00e9der aux outputs des t\u00e2ches et, entre autres, t\u00e9l\u00e9charger les fichiers CSV g\u00e9n\u00e9r\u00e9s par le flow.<\/p>\n<img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-04.png?resize=640%2C468&#038;ssl=1\" alt=\"\" width=\"640\" height=\"468\" class=\"alignnone size-large wp-image-1631\" srcset=\"https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-04.png?resize=1024%2C749&amp;ssl=1 1024w, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-04.png?resize=300%2C219&amp;ssl=1 300w, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-04.png?resize=768%2C562&amp;ssl=1 768w, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-04.png?resize=1536%2C1124&amp;ssl=1 1536w, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-04.png?resize=369%2C270&amp;ssl=1 369w, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-04.png?w=1590&amp;ssl=1 1590w, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-04.png?w=1280&amp;ssl=1 1280w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/>\n<h2>Trigger<\/h2>\n<p>Par d\u00e9faut, un flow ne peut \u00eatre lanc\u00e9 que manuellement via l&rsquo;interface graphique ou l&rsquo;API de Kestra.<\/p>\n<p>Il est possible de d\u00e9clancher un flow depuis un \u00e9v\u00e8nement ext\u00e9rieur, c&rsquo;est le r\u00f4le du trigger.<\/p>\n<p>Kestra inclu de base trois triggers: <strong>flow<\/strong>, qui permet de d\u00e9clancher un flow depuis un autre flow, <strong>webhook<\/strong> qui permet de d\u00e9clancher un flow depuis une URL webhook et <strong>schedule<\/strong> qui permet de d\u00e9clencher un flow p\u00e9riodiquement depuis une expression cron. De nombreux autres triggers sont disponibles au sein des plugins de Kestra et permettent de d\u00e9clancher un flow depuis un message dans un broker, un fichier, ou la pr\u00e9sence d&rsquo;un enregistrement dans une table de base de donn\u00e9es par exemple.<\/p>\n<p>L&rsquo;exemple suivant va d\u00e9clencher un flow toutes les minutes, il utilise une cron expression pour d\u00e9finir sa p\u00e9riodicit\u00e9 de d\u00e9clenchement.<\/p>\n<pre lang=\"yaml\">\nid: flow-with-trigger\nnamespace: fr.loicmathieu.example\n\ntriggers:\n  - id: schedule\n    type: io.kestra.core.models.triggers.types.Schedule\n    cron: \"*\/1 * * * *\"\n\ntasks:\n  - id: \"echo\"\n    type: \"io.kestra.core.tasks.debugs.Echo\"\n    format: \"{{task.id}} &gt; {{taskrun.startDate}}\"\n<\/pre>\n<h2>Traitement de donn\u00e9e avec Python et Pandas<\/h2>\n<p>Kestra offre des fonctionnalit\u00e9s avanc\u00e9es via des t\u00e2ches permettant d&rsquo;ex\u00e9cuter des scripts Bash, Python ou NodeJS.<\/p>\n<p>L&rsquo;exemple suivant va requ\u00eater le m\u00eame dataset BigQuery des pages vues Wikipedia, l&rsquo;\u00e9crire au format CSV, puis utiliser ce CSV dans une t\u00e2che de type <code>io.kestra.core.tasks.scripts.Python<\/code> qui permet de lancer un script Python.<\/p>\n<p>Cette t\u00e2che prend en propri\u00e9t\u00e9s :<\/p>\n<ul><li><code>inputFiles<\/code> : une liste de fichier qui doit contenir le fichier <code>main.py<\/code> qui sera appel\u00e9 par la t\u00e2che. Un deuxi\u00e8me ficher <code>data.csv<\/code> est d\u00e9fini qui va permettre d&rsquo;acc\u00e9der localement au fichier cr\u00e9\u00e9 par la t\u00e2che <strong>write-csv<\/strong>. Kestra va automatiquement le r\u00e9cup\u00e9rer depuis son internal storage et le mettre \u00e0 disposition dans le r\u00e9pertoire de travail de la t\u00e2che Python.<\/li>\n\n<li><code>requirements<\/code> : une liste de d\u00e9pendances pip, ici, nous avons mis la librairie Pandas qui permet d&rsquo;analyser les donn\u00e9es du fichier CSV.<\/li>\n<\/ul>\n<pre>\nid: wikipedia-top-ten-pyhton-panda\nnamespace: fr.loicmathieu.example\ndescription: A flow that loads wikipedia top 10 FR pages each hour\n\ntasks:\n  - id: query-top-ten\n    type: io.kestra.plugin.gcp.bigquery.Query\n    serviceAccount: \"\"\n    sql: |\n      SELECT DATETIME(datehour) as date, title, views \n      FROM `bigquery-public-data.wikipedia.pageviews_2023` \n      WHERE DATE(datehour) = current_date() and wiki = 'fr' and title not in ('Cookie_(informatique)', 'Wikip\u00e9dia:Accueil_principal', 'Sp\u00e9cial:Recherche')\n      ORDER BY datehour desc, views desc\n      LIMIT 10\n    store: true\n  - id: write-csv\n    type: io.kestra.plugin.serdes.csv.CsvWriter\n    from: \"{{outputs['query-top-ten'].uri}}\"\n  - id: \"python\"\n    type: io.kestra.core.tasks.scripts.Python\n    inputFiles:\n      data.csv: \"{{outputs['write-csv'].uri}}\"\n      main.py: |\n        import pandas as pd\n        from kestra import Kestra\n        data = pd.read_csv(\"data.csv\")\n        data.info()\n        sumOfViews = data['views'].sum()\n        Kestra.outputs({'sumOfViews': int(sumOfViews)})\n    requirements:\n      - pandas\n<\/pre>\n<p>Le script Python va utiliser Pandas pour lire le fichier CSV et le transformer en data frame Pandas, puis r\u00e9aliser la somme de la colonne <strong>views<\/strong>. Cette somme sera ensuite mise en output de la t\u00e2che gr\u00e2ce \u00e0 la librairie Python Kestra.<\/p>\n<p>Voici les logs d&rsquo;ex\u00e9cution de ce flow.<\/p>\n<img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-05.png?resize=640%2C259&#038;ssl=1\" alt=\"\" width=\"640\" height=\"259\" class=\"alignnone size-large wp-image-1632\" srcset=\"https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-05.png?resize=1024%2C414&amp;ssl=1 1024w, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-05.png?resize=300%2C121&amp;ssl=1 300w, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-05.png?resize=768%2C311&amp;ssl=1 768w, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-05.png?resize=1536%2C621&amp;ssl=1 1536w, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-05.png?resize=604%2C244&amp;ssl=1 604w, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-05.png?w=1610&amp;ssl=1 1610w, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-05.png?w=1280&amp;ssl=1 1280w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/>\n<h2>Conclusion<\/h2>\n<p>Dans cet article introductif, nous avons vu les principaux concepts de Kestra et quelques exemples de flow.<\/p>\n<p>Pour aller plus loin, vous pouvez consulter la <a href=\"https:\/\/kestra.io\/docs\/\" rel=\"noopener\" target=\"_blank\">documentation en ligne<\/a> ainsi que la <a href=\"https:\/\/kestra.io\/plugins\/\" rel=\"noopener\" target=\"_blank\">liste des plugins<\/a>.<\/p>\n<p>Ketra est un projet communautaire open source disponible sur GitHub, n&rsquo;h\u00e9sitez pas \u00e0 :<\/p>\n<ul><li>Mettre une \u00e9toile ou ouvrir une issue sur son <a href=\"https:\/\/github.com\/kestra-io\/kestra\" rel=\"noopener\" target=\"_blank\">repository<\/a>.<\/li>\n\n<li>Suivre Kestra sur <a href=\"https:\/\/twitter.com\/kestra_io\" rel=\"noopener\" target=\"_blank\">Twitter<\/a> ou <a href=\"https:\/\/www.linkedin.com\/company\/kestra\/\" rel=\"noopener\" target=\"_blank\">Linkedin<\/a>.<\/li>\n\n<li>Contacter l&rsquo;\u00e9quipe sur <a href=\"https:\/\/api.kestra.io\/v1\/communities\/slack\/redirect\" rel=\"noopener\" target=\"_blank\">Slack<\/a><\/li>\n<\/ul>\n<p><\/p>","protected":false},"excerpt":{"rendered":"<p>Kestra est un orchestrateur et scheduler de donn\u00e9e open source. Avec Kestra, les workflows de donn\u00e9es, appel\u00e9s flows, utilisent le format YAML et sont ex\u00e9cut\u00e9s par son moteur via un appel API, l&rsquo;interface utilisateur, ou un trigger (webhook, schedule, SQL query, Pub\/Sub message, \u2026). Les notions importantes de Kestra sont : Le flow : qui d\u00e9crit la mani\u00e8re dont la donn\u00e9e sera orchestr\u00e9e (le workflow donc). C&rsquo;est une suite de tasks. La task : une \u00e9tape du flow qui va&#8230;<p class=\"read-more\"><a class=\"btn btn-default\" href=\"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/informatique\/introduction-a-kestra\/\">Lire la suite<span class=\"screen-reader-text\"> Lire la suite<\/span><\/a><\/p><\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"activitypub_content_warning":"","activitypub_content_visibility":"","activitypub_max_image_attachments":4,"activitypub_interaction_policy_quote":"anyone","activitypub_status":"","footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[9],"tags":[211,212],"class_list":["post-1611","post","type-post","status-publish","format-standard","hentry","category-informatique","tag-kestra","tag-orchestrator"],"aioseo_notices":[],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"jetpack-related-posts":[{"id":1786,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/informatique\/concevoir-un-saas-multitenant\/","url_meta":{"origin":1611,"position":0},"title":"Concevoir un SaaS multitenant","author":"admin","date":"mardi  5 mars 2024","format":false,"excerpt":"Cet article se repose sur mon talk Concevoir un SaaS multitenant fait \u00e0 Cloud Nord le 12 octobre 2023. Kestra est une plate-forme d\u2019orchestration et de scheduling de donn\u00e9e hautement scalabe, qui cr\u00e9e, ex\u00e9cute, planifie et surveille des millions de pipelines complexes. Pour une introduction \u00e0 Kestra, vous pouvez lire\u2026","rel":"","context":"Dans &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/category\/informatique\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-software-architecture-1024x576.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-software-architecture-1024x576.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/kestra-software-architecture-1024x576.png?resize=525%2C300&ssl=1 1.5x"},"classes":[]},{"id":1606,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/informatique\/au-revoir-zenika-bonjour-kestra\/","url_meta":{"origin":1611,"position":1},"title":"Au revoir Zenika, bonjour Kestra","author":"admin","date":"mardi 10 janvier 2023","format":false,"excerpt":"Apr\u00e8s 4 ans, 4 mois et 4 jours (ou presque), je quitte Zenika. Ces 4 ann\u00e9es et quelques auront \u00e9t\u00e9 parmi les plus passionnantes de ma vie professionnelle. Je suis triste de quitter cette super soci\u00e9t\u00e9 dans laquelle j'ai pu m'\u00e9panouir, grandir et apprendre plein de choses. Je suis s\u00fbr\u2026","rel":"","context":"Dans &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/category\/informatique\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1650,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/informatique\/le-profiler-sql-de-visualvm\/","url_meta":{"origin":1611,"position":2},"title":"Le profiler SQL de VisualVM","author":"admin","date":"mardi  4 avril 2023","format":false,"excerpt":"Il y a peu, j'ai d\u00e9couvert le profiler SQL de VisualVM et je me suis dit que je devais aussi vous le faire d\u00e9couvrir ;). VisualVM est un outil qui fournit une interface visuelle pour afficher des informations d\u00e9taill\u00e9es sur les applications qui s'ex\u00e9cutent sur une machine virtuelle Java (JVM).\u2026","rel":"","context":"Dans &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/category\/informatique\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/Capture-decran-du-2023-04-03-14-17-25-1024x624.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/Capture-decran-du-2023-04-03-14-17-25-1024x624.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/Capture-decran-du-2023-04-03-14-17-25-1024x624.png?resize=525%2C300&ssl=1 1.5x"},"classes":[]},{"id":2007,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/informatique\/characterescapes-la-perle-cachee-de-jackson\/","url_meta":{"origin":1611,"position":3},"title":"CharacterEscapes: la perle cach\u00e9e de Jackson","author":"admin","date":"mercredi 10 septembre 2025","format":false,"excerpt":"A Kestra, la plateforme d'orchestration de donn\u00e9es pour laquelle je travaille, on a eu une issue (#10326) ouverte d'un utilisateur qui rapportait un probl\u00e8me avec la base PostgreSQL et le caract\u00e8re Unicode \\u0000. Une t\u00e2che de workflow qui retournait ce caract\u00e8re en outpout plantait. Apr\u00e8s investigation, PostgreSQL refuse de stocker\u2026","rel":"","context":"Dans &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/category\/informatique\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1847,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/informatique\/jooq-tip-ne-convertissez-pas-jsonb-en-string\/","url_meta":{"origin":1611,"position":4},"title":"jOOQ tip: ne convertissez pas JSONB en String","author":"admin","date":"mercredi 23 octobre 2024","format":false,"excerpt":"Il y a quelques semaines, en investiguant de possibles am\u00e9liorations de performance pour le backend JDBC de Kestra, j'ai remarqu\u00e9 qu'une m\u00e9thode qu'on utilisait pour mapper une entit\u00e9 \u00e0 persister en base de donn\u00e9es dans sa repr\u00e9sentation JSONB prenait beaucoup de temps dans nos profiles CPU. Dans le flame graph\u2026","rel":"","context":"Dans &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/category\/informatique\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/366507373-c44206a5-0085-43cc-902e-97756319b0ea-1024x737.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/366507373-c44206a5-0085-43cc-902e-97756319b0ea-1024x737.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/366507373-c44206a5-0085-43cc-902e-97756319b0ea-1024x737.png?resize=525%2C300&ssl=1 1.5x"},"classes":[]},{"id":1731,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/informatique\/optimisation-dindex-postgresql\/","url_meta":{"origin":1611,"position":5},"title":"Optimisation d&rsquo;index PostgreSQL","author":"admin","date":"mardi 22 ao\u00fbt 2023","format":false,"excerpt":"Il y a quelque temps, j\u2019avais travaill\u00e9 sur des optimisations de temps d'ex\u00e9cution de requ\u00eates pour PostgreSQL, j'en parle ici : LE PROFILER SQL DE VISUALVM. Kestra est une plate-forme d\u2019orchestration et de scheduling de donn\u00e9e hautement scalable, qui cr\u00e9e, ex\u00e9cute, planifie, et surveille des millions de pipelines complexes. C\u2019est\u2026","rel":"","context":"Dans &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/category\/informatique\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/wp-json\/wp\/v2\/posts\/1611","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/wp-json\/wp\/v2\/comments?post=1611"}],"version-history":[{"count":25,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/wp-json\/wp\/v2\/posts\/1611\/revisions"}],"predecessor-version":[{"id":1648,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/wp-json\/wp\/v2\/posts\/1611\/revisions\/1648"}],"wp:attachment":[{"href":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/wp-json\/wp\/v2\/media?parent=1611"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/wp-json\/wp\/v2\/categories?post=1611"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/wp-json\/wp\/v2\/tags?post=1611"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}