{"id":479,"date":"2022-05-04T07:03:00","date_gmt":"2022-05-04T10:03:00","guid":{"rendered":"https:\/\/suspensao.blog.br\/descrenca\/?p=479"},"modified":"2022-05-03T17:12:29","modified_gmt":"2022-05-03T20:12:29","slug":"dois-problemas-num-jenkinsfile","status":"publish","type":"post","link":"https:\/\/suspensao.blog.br\/descrenca\/dois-problemas-num-jenkinsfile\/","title":{"rendered":"Dois problemas num Jenkinsfile"},"content":{"rendered":"\n<div class=\"wp-block-cover has-background-dim\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"650\" height=\"225\" data-attachment-id=\"483\" data-permalink=\"https:\/\/suspensao.blog.br\/descrenca\/dois-problemas-num-jenkinsfile\/self-operating_napkin_rube_goldberg_cartoon_with_caption\/\" data-orig-file=\"https:\/\/i0.wp.com\/suspensao.blog.br\/descrenca\/wp-content\/uploads\/2022\/05\/Self-operating_napkin_Rube_Goldberg_cartoon_with_caption.jpg?fit=650%2C225&amp;ssl=1\" data-orig-size=\"650,225\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"Self-operating_napkin_Rube_Goldberg_cartoon_with_caption\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/suspensao.blog.br\/descrenca\/wp-content\/uploads\/2022\/05\/Self-operating_napkin_Rube_Goldberg_cartoon_with_caption.jpg?fit=300%2C104&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/suspensao.blog.br\/descrenca\/wp-content\/uploads\/2022\/05\/Self-operating_napkin_Rube_Goldberg_cartoon_with_caption.jpg?fit=650%2C225&amp;ssl=1\" class=\"wp-block-cover__image-background wp-image-483\" alt=\"\" src=\"https:\/\/i0.wp.com\/suspensao.blog.br\/descrenca\/wp-content\/uploads\/2022\/05\/Self-operating_napkin_Rube_Goldberg_cartoon_with_caption.jpg?resize=650%2C225&#038;ssl=1\" data-object-fit=\"cover\" srcset=\"https:\/\/i0.wp.com\/suspensao.blog.br\/descrenca\/wp-content\/uploads\/2022\/05\/Self-operating_napkin_Rube_Goldberg_cartoon_with_caption.jpg?w=650&amp;ssl=1 650w, https:\/\/i0.wp.com\/suspensao.blog.br\/descrenca\/wp-content\/uploads\/2022\/05\/Self-operating_napkin_Rube_Goldberg_cartoon_with_caption.jpg?resize=300%2C104&amp;ssl=1 300w\" sizes=\"auto, (max-width: 650px) 100vw, 650px\" \/><div class=\"wp-block-cover__inner-container is-layout-flow wp-block-cover-is-layout-flow\">\n<p class=\"has-text-align-center has-large-font-size\">Ah, as sutilezas do shell script&#8230;<\/p>\n<\/div><\/div>\n\n\n\n<p>J\u00e1 usei v\u00e1rios servidores Jenkins aqui na Liferay, sempre como desenvolvedor. Na Liferay Cloud, por\u00e9m, configurar e rodar Jenkins \u00e9 uma tarefa rotineira. Resolvi ent\u00e3o refor\u00e7ar meu conhecimento seguindo os passos de <a href=\"https:\/\/www.jenkins.io\/doc\/pipeline\/tour\/getting-started\"><em>Guided Tour to Jenkins<\/em><\/a>. Foi quando aconteceu uma coisa curiosa.<\/p>\n\n\n\n<p>O processo de <em>build<\/em> no Jenkins \u00e9 definidos por arquivos Jenkinsfile. Um Jenkinsfile cont\u00e9m, entre outras coisas, v\u00e1rios est\u00e1gios do processo de build. Cada est\u00e1gio possui um ou mais <em>passos<\/em> (isto \u00e9, comandos a serem executados). <\/p>\n\n\n\n<p>A <a href=\"https:\/\/www.jenkins.io\/doc\/pipeline\/tour\/running-multiple-steps\/\">sess\u00e3o sobre passos m\u00faltiplos<\/a> me apresentou o <kbd>retry<\/kbd> (que executa um um passo at\u00e9 ele ser bem-sucedido) e <kbd>timeout<\/kbd> (que limita o tempo que um passo pode tomar). Para test\u00e1-los, escrevi o seguinte no meu Jenkinsfile:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">pipeline {\n  agent any\n  stages {\n    stage(<span class=\"hljs-string\">'build'<\/span>) {\n      steps {\n        retry(<span class=\"hljs-number\">3<\/span>) {\n          sh <span class=\"hljs-string\">''<\/span><span class=\"hljs-string\">'\n            R=$(od -An -N1 -i \/dev\/random)\n            echo trying flakey... \n            &#91; $((R % 3)) -eq 0 ] &amp;&amp; exit 1\n          '<\/span><span class=\"hljs-string\">''<\/span>\n        }\n        timeout(time: <span class=\"hljs-number\">5<\/span>, unit: <span class=\"hljs-string\">'SECONDS'<\/span>) {\n          sh <span class=\"hljs-string\">''<\/span><span class=\"hljs-string\">'\n            R=$(od -An -N1 -i \/dev\/random)\n            sh '<\/span><span class=\"hljs-keyword\">echo<\/span> trying slow...\n                      &#91; $((R % <span class=\"hljs-number\">3<\/span>)) -eq <span class=\"hljs-number\">0<\/span> ] &amp;&amp; sleep <span class=\"hljs-number\">10<\/span>\n          <span class=\"hljs-string\">''<\/span><span class=\"hljs-string\">'\n         }\n       }\n    }\n  }\n}<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Mesmo que voc\u00ea n\u00e3o conhe\u00e7a Jenkinsfiles, \u00e9 poss\u00edvel ter uma ideia do que se passa:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>No <kbd>retry(3)<\/kbd>, coloquei um script shell que, a cada tr\u00eas execu\u00e7\u00f5es, falha. Assim, poderia ver Jenkins fazendo novas tentativas de execut\u00e1-lo.<\/li><li>No passo de <kbd>timeout(5, SECONDS)<\/kbd> h\u00e1 um script que, a cada tr\u00eas execu\u00e7\u00f5es, demora dez segundos para terminar. Como h\u00e1 um tempo-limite de 5 segundos, essas execu\u00e7\u00f5es demoradas v\u00e3o falhar.<\/li><\/ul>\n\n\n\n<p>Mandei o aquivo para <a href=\"https:\/\/github.com\/brandizzi\/jenkinstest\/\">GitHub<\/a> configurei Jenkins para &#8220;buildar&#8221; o reposit\u00f3rio e&#8230; todos os <em>builds<\/em> falharam! Isto n\u00e3o estava certo, eu esperava que o <em>build<\/em> falhasse pouco mais de um ter\u00e7o das vezes. O que estava acontecendo?<\/p>\n\n\n\n<p>O problema \u00e9 que, na minha cabe\u00e7a, a condi\u00e7\u00e3o do teste <kbd>[ $((R % 3)) -eq 0 ] &amp;&amp; exit 1<\/kbd> seria verdadeira um ter\u00e7o das vezes, fazendo com que o script encerrasse com status 1. (Todo status n\u00e3o-nulo \u00e9 considerado falha.) S\u00f3 que, quando a condi\u00e7\u00e3o era falsa, o pr\u00f3prio teste falhava. Era o status do teste que Jenkins verificava! <\/p>\n\n\n\n<p>Entendido o problema, foi f\u00e1cil resolver: adicionei, ao final do script, um operador OU. Por qu\u00ea? Porque se o teste passar, o <kbd>exit 1<\/kbd> \u00e9 executado e o script falha; se o teste n\u00e3o passar, por\u00e9m, o sh vai executar o comando depois do <kbd>||<\/kbd>, que sempre vai retornar zero.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">pipeline {\n  agent any\n  stages {\n    stage(<span class=\"hljs-string\">'build'<\/span>) {\n      steps {\n        retry(<span class=\"hljs-number\">3<\/span>) {\n          sh <span class=\"hljs-string\">''<\/span><span class=\"hljs-string\">'\n            R=$(od -An -N1 -i \/dev\/random)\n            echo trying flakey... \n            &#91; $((R % 3)) -eq 0 ] &amp;&amp; exit 1 || echo '<\/span>flakey ok<span class=\"hljs-string\">'\n          '<\/span><span class=\"hljs-string\">''<\/span>\n        }\n        timeout(time: <span class=\"hljs-number\">5<\/span>, unit: <span class=\"hljs-string\">'SECONDS'<\/span>) {\n          sh <span class=\"hljs-string\">''<\/span><span class=\"hljs-string\">'\n            R=$(od -An -N1 -i \/dev\/random)\n            sh '<\/span><span class=\"hljs-keyword\">echo<\/span> trying slow...\n            &#91; $((R % <span class=\"hljs-number\">3<\/span>)) -eq <span class=\"hljs-number\">0<\/span> ] &amp;&amp; sleep <span class=\"hljs-number\">10<\/span> || <span class=\"hljs-keyword\">echo<\/span> <span class=\"hljs-string\">'slow ok'<\/span>\n          <span class=\"hljs-string\">''<\/span><span class=\"hljs-string\">'\n        }\n      }\n    }\n  }\n}<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Funcionou! Exceto que agora o <em>build<\/em> raramente falhava, e nunca por tempo excedido. Por que ser\u00e1?<\/p>\n\n\n\n<p>\u00c9 que concatenei  <kbd>|| echo 'slow ok'<\/kbd> tamb\u00e9m na frente do passo do <em>timeout<\/em>. O script desse passo de fato levava 10 segundos para executar um ter\u00e7o das vezes, e Jenkins de fato cancelava o script. <\/p>\n\n\n\n<p>O problema \u00e9 que Jenkins &#8220;mata&#8221; o comando <kbd>sleep 10<\/kbd>, que ent\u00e3o retorna um status de erro. S\u00f3 que o<kbd> echo 'slow ok'<\/kbd> tamb\u00e9m &#8220;come&#8221; esse status de falha quando o <em>build<\/em> \u00e9 cancelado. Por isso, mesmo quando abortado, o <em>build<\/em> aparecia como bem-sucedido. Por outro lado, eu n\u00e3o poderia simplesmente deixar o teste falhar, como antes.<\/p>\n\n\n\n<p>A solu\u00e7\u00e3o \u00e9 aquela t\u00e3o comum: parar de usar truquezinhos engenhosos e escrever c\u00f3digo claro. Troquei os <kbd>&amp;&amp;<\/kbd> e <kbd>||<\/kbd> por um condicional <kbd>if<\/kbd>. Convenhamos que at\u00e9 mais leg\u00edvel ficou, n\u00e9?<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">pipeline {\n  agent any\n  stages {\n    stage(<span class=\"hljs-string\">'build'<\/span>) {\n      steps {\n        retry(<span class=\"hljs-number\">3<\/span>) {\n          sh <span class=\"hljs-string\">''<\/span><span class=\"hljs-string\">'\n            R=$(od -An -N1 -i \/dev\/random)\n            echo trying flakey... \n            &#91; $((R % 3)) -eq 0 ] &amp;&amp; exit 1 || echo '<\/span>flakey ok<span class=\"hljs-string\">'\n          '<\/span><span class=\"hljs-string\">''<\/span>\n        }\n        timeout(time: <span class=\"hljs-number\">5<\/span>, unit: <span class=\"hljs-string\">'SECONDS'<\/span>) {\n          sh <span class=\"hljs-string\">''<\/span><span class=\"hljs-string\">'\n            R=$(od -An -N1 -i \/dev\/random)\n            sh '<\/span><span class=\"hljs-keyword\">echo<\/span> trying slow...\n            <span class=\"hljs-keyword\">if<\/span> &#91; $((R % <span class=\"hljs-number\">3<\/span>)) -eq <span class=\"hljs-number\">0<\/span> ] ; then \n              sleep <span class=\"hljs-number\">10<\/span>\n            fi\n          <span class=\"hljs-string\">''<\/span><span class=\"hljs-string\">'\n        }\n      }\n    }\n  }\n}<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>\u00c0s vezes sinto que estamos na era CVS das ferramentas de CI, aguardando um Subversion que simplifique nossa vida. Mas confesso estar feliz que tenhamos, hoje essas ferramentas dispon\u00edveis. Por ora, vou focando em aprender com esses incidentes.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>J\u00e1 usei v\u00e1rios servidores Jenkins aqui na Liferay, sempre como desenvolvedor. Na Liferay Cloud, por\u00e9m, configurar e rodar Jenkins \u00e9 uma tarefa rotineira. Resolvi ent\u00e3o refor\u00e7ar meu conhecimento seguindo os passos de Guided Tour to Jenkins. Foi quando aconteceu uma coisa curiosa. O processo de build no Jenkins \u00e9 definidos por arquivos Jenkinsfile. Um Jenkinsfile [&hellip;]<\/p>\n","protected":false},"author":2,"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,"footnotes":"","jetpack_publicize_message":"As pegadinhas do shell script, junto com as pegadinhas do Jenkins, sempre nos trazem alguma divers\u00e3o, n\u00e9?","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":[147,148,27],"tags":[143,144,141,142,145,91],"class_list":["post-479","post","type-post","status-publish","format-standard","hentry","category-continuous-integration","category-jenkins","category-shell-script","tag-cd","tag-ci","tag-continuous-delivery","tag-continuous-integration","tag-jenkins","tag-shell-script"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p23QLV-7J","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/suspensao.blog.br\/descrenca\/wp-json\/wp\/v2\/posts\/479","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/suspensao.blog.br\/descrenca\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/suspensao.blog.br\/descrenca\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/suspensao.blog.br\/descrenca\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/suspensao.blog.br\/descrenca\/wp-json\/wp\/v2\/comments?post=479"}],"version-history":[{"count":7,"href":"https:\/\/suspensao.blog.br\/descrenca\/wp-json\/wp\/v2\/posts\/479\/revisions"}],"predecessor-version":[{"id":496,"href":"https:\/\/suspensao.blog.br\/descrenca\/wp-json\/wp\/v2\/posts\/479\/revisions\/496"}],"wp:attachment":[{"href":"https:\/\/suspensao.blog.br\/descrenca\/wp-json\/wp\/v2\/media?parent=479"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/suspensao.blog.br\/descrenca\/wp-json\/wp\/v2\/categories?post=479"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/suspensao.blog.br\/descrenca\/wp-json\/wp\/v2\/tags?post=479"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}