| |
| |
| |
| |
| <!DOCTYPE html> |
| <!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]--> |
| <!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]--> |
| <html xmlns="http://www.w3.org/1999/xhtml"> |
| <head> |
| <meta charset="utf-8" /> |
| <meta name="viewport" content="width=device-width, initial-scale=1"> |
| <title>Best Practices — Airflow Documentation</title> |
| <link rel="stylesheet" href="_static/_gen/css/main.min.css" type="text/css" /> |
| <link rel="stylesheet" type="text/css" href="_static/copybutton.css" /> |
| <link rel="stylesheet" type="text/css" href="_static/_gen/css/main-custom.min.css" /> |
| <link rel="stylesheet" type="text/css" href="_static/graphviz.css" /> |
| <link rel="shortcut icon" href="_static/pin_32.png"/> |
| <link rel="index" title="Index" href="genindex.html" /> |
| <link rel="search" title="Search" href="search.html" /> |
| <link rel="next" title="Production Deployment" href="production-deployment.html" /> |
| <link rel="prev" title="Changelog" href="changelog.html" /> |
| <script type="application/javascript"> |
| var doNotTrack = false; |
| window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date; |
| ga('create', 'UA-140539454-1', 'auto'); |
| ga('send', 'pageview'); |
| </script> |
| <script async src='https://www.google-analytics.com/analytics.js'></script> |
| |
| |
| </head><body class="td-section"> |
| |
| |
| <header> |
| <nav class="js-navbar-scroll navbar"> |
| <div class="navbar__icon-container"> |
| <a href="/"> |
| <svg xmlns="http://www.w3.org/2000/svg" width="155.314" height="60" viewBox="0 0 155.314 60"> |
| <defs> |
| <clipPath id="clip-path"> |
| <path id="Rectangle_1" d="M0 0h155.314v60H0z" fill="none" data-name="Rectangle 1"></path> |
| </clipPath> |
| </defs> |
| <g id="logo" transform="translate(-1305 -780.355)"> |
| <g id="Group_2" clip-path="url(#clip-path)" data-name="Group 2" transform="translate(1305 780.355)"> |
| <g id="Group_1" data-name="Group 1" transform="translate(.486 .486)"> |
| <path id="Path_1" d="M1307.562 880.867l28.187-28.893a.521.521 0 0 0 .063-.666c-1.714-2.393-4.877-2.808-6.049-4.416-3.472-4.763-4.353-7.459-5.845-7.292a.456.456 0 0 0-.271.143l-10.182 10.438c-5.858 6-6.7 19.225-6.852 30.3a.552.552 0 0 0 .949.386z" fill="#017cee" data-name="Path 1" transform="translate(-1306.613 -822.232)"></path> |
| <path id="Path_2" d="M1405.512 908.489l-28.893-28.189a.521.521 0 0 0-.667-.063c-2.393 1.715-2.808 4.877-4.416 6.049-4.763 3.472-7.459 4.353-7.292 5.845a.456.456 0 0 0 .143.27l10.438 10.182c6 5.858 19.225 6.7 30.3 6.852a.552.552 0 0 0 .387-.946z" fill="#00ad46" data-name="Path 2" transform="translate(-1346.876 -850.567)"></path> |
| <path id="Path_3" d="M1373.909 902.252c-3.28-3.2-4.8-9.53 1.486-22.583-10.219 4.567-13.8 10.57-12.039 12.289z" fill="#04d659" data-name="Path 3" transform="translate(-1345.96 -850.233)"></path> |
| <path id="Path_4" d="M1433.132 782.359l-28.186 28.893a.52.52 0 0 0-.063.666c1.715 2.393 4.876 2.808 6.049 4.416 3.472 4.763 4.354 7.459 5.845 7.292a.454.454 0 0 0 .271-.143l10.182-10.438c5.858-6 6.7-19.225 6.852-30.3a.553.553 0 0 0-.95-.386z" fill="#00c7d4" data-name="Path 4" transform="translate(-1375.21 -782.123)"></path> |
| <path id="Path_5" d="M1426.9 881.155c-3.2 3.28-9.53 4.8-22.584-1.486 4.567 10.219 10.57 13.8 12.289 12.039z" fill="#11e1ee" data-name="Path 5" transform="translate(-1374.875 -850.233)"></path> |
| <path id="Path_6" d="M1307 782.919l28.893 28.186a.521.521 0 0 0 .666.063c2.393-1.715 2.808-4.877 4.416-6.049 4.763-3.472 7.459-4.353 7.292-5.845a.459.459 0 0 0-.143-.271l-10.438-10.182c-6-5.858-19.225-6.7-30.3-6.852a.552.552 0 0 0-.386.95z" fill="#e43921" data-name="Path 6" transform="translate(-1306.766 -781.97)"></path> |
| <path id="Path_7" d="M1405.8 804.711c3.28 3.2 4.8 9.53-1.486 22.584 10.219-4.567 13.8-10.571 12.039-12.289z" fill-rule="evenodd" fill="#ff7557" data-name="Path 7" transform="translate(-1374.875 -797.859)"></path> |
| <path id="Path_8" d="M1329.355 849.266c3.2-3.28 9.53-4.8 22.584 1.486-4.567-10.219-10.57-13.8-12.289-12.039z" fill="#0cb6ff" data-name="Path 8" transform="translate(-1322.503 -821.316)"></path> |
| <circle id="Ellipse_1" cx="1.26" cy="1.26" r="1.26" fill="#4a4848" data-name="Ellipse 1" transform="translate(28.18 28.171)"></circle> |
| <path id="Path_9" d="M1527.558 827.347a.229.229 0 0 1-.223-.223.458.458 0 0 1 .011-.123l2.766-7.214a.346.346 0 0 1 .357-.245h.758a.348.348 0 0 1 .357.245l2.754 7.214.022.123a.228.228 0 0 1-.223.223h-.568a.288.288 0 0 1-.19-.056.352.352 0 0 1-.089-.134l-.613-1.583h-3.657l-.613 1.583a.317.317 0 0 1-.1.134.269.269 0 0 1-.178.056zm4.795-2.732l-1.505-3.958-1.505 3.958zm3.322 4.85a.258.258 0 0 1-.189-.078.241.241 0 0 1-.067-.178v-7.4a.241.241 0 0 1 .067-.178.258.258 0 0 1 .189-.078h.513a.268.268 0 0 1 .256.256v.49a2.118 2.118 0 0 1 1.828-.858 2.092 2.092 0 0 1 1.751.736 3.135 3.135 0 0 1 .636 1.9q.011.122.011.379t-.011.379a3.168 3.168 0 0 1-.636 1.9 2.111 2.111 0 0 1-1.751.736 2.154 2.154 0 0 1-1.806-.836v2.587a.241.241 0 0 1-.067.178.223.223 0 0 1-.179.078zm2.364-2.91a1.324 1.324 0 0 0 1.149-.491 2.266 2.266 0 0 0 .4-1.293q.011-.111.011-.323 0-2.107-1.562-2.107a1.365 1.365 0 0 0-1.159.513 2.111 2.111 0 0 0-.412 1.2l-.012.424.012.435a1.862 1.862 0 0 0 .424 1.149 1.4 1.4 0 0 0 1.148.493zm5.628.9a2.329 2.329 0 0 1-1.015-.223 1.94 1.94 0 0 1-.747-.6 1.487 1.487 0 0 1-.268-.859 1.459 1.459 0 0 1 .6-1.2 3.4 3.4 0 0 1 1.65-.624l1.661-.234v-.323q0-1.137-1.3-1.137a1.4 1.4 0 0 0-.8.212 1.376 1.376 0 0 0-.468.48.305.305 0 0 1-.089.145.18.18 0 0 1-.134.045h-.48a.23.23 0 0 1-.245-.245 1.17 1.17 0 0 1 .245-.6 1.931 1.931 0 0 1 .747-.591 2.7 2.7 0 0 1 1.238-.256 2.351 2.351 0 0 1 1.8.591 2.032 2.032 0 0 1 .547 1.45v3.613a.257.257 0 0 1-.078.19.24.24 0 0 1-.178.067h-.513a.233.233 0 0 1-.257-.256v-.479a1.923 1.923 0 0 1-.714.6 2.557 2.557 0 0 1-1.203.237zm.234-.836a1.579 1.579 0 0 0 1.182-.469 1.881 1.881 0 0 0 .468-1.371v-.312l-1.293.19a2.918 2.918 0 0 0-1.193.379.761.761 0 0 0-.4.658.784.784 0 0 0 .368.691 1.585 1.585 0 0 0 .867.237zm6.643.836a2.556 2.556 0 0 1-1.873-.669 2.738 2.738 0 0 1-.714-1.9l-.011-.446.011-.446a2.7 2.7 0 0 1 .714-1.885 2.531 2.531 0 0 1 1.873-.68 2.917 2.917 0 0 1 1.36.29 2.077 2.077 0 0 1 .825.714 1.7 1.7 0 0 1 .3.848.2.2 0 0 1-.067.178.281.281 0 0 1-.19.067h-.535a.265.265 0 0 1-.168-.045.458.458 0 0 1-.111-.178 1.428 1.428 0 0 0-.535-.758 1.516 1.516 0 0 0-.87-.234 1.45 1.45 0 0 0-1.1.435 1.952 1.952 0 0 0-.435 1.3l-.011.4.011.379a1.969 1.969 0 0 0 .435 1.316 1.446 1.446 0 0 0 1.1.424 1.577 1.577 0 0 0 .87-.223 1.493 1.493 0 0 0 .535-.769.458.458 0 0 1 .111-.178.228.228 0 0 1 .168-.056h.535a.258.258 0 0 1 .19.078.2.2 0 0 1 .067.178 1.75 1.75 0 0 1-.3.847 2.078 2.078 0 0 1-.825.714 2.876 2.876 0 0 1-1.361.302zm4.078-.112a.233.233 0 0 1-.257-.256v-7.4a.241.241 0 0 1 .067-.178.259.259 0 0 1 .19-.078h.557a.267.267 0 0 1 .257.256v2.6a2.167 2.167 0 0 1 .758-.624 2.353 2.353 0 0 1 1.082-.223 2.067 2.067 0 0 1 1.661.691 2.642 2.642 0 0 1 .6 1.818v3.144a.257.257 0 0 1-.078.19.24.24 0 0 1-.178.067h-.557a.233.233 0 0 1-.256-.256V824a1.775 1.775 0 0 0-.39-1.227 1.387 1.387 0 0 0-1.1-.435 1.481 1.481 0 0 0-1.126.446 1.7 1.7 0 0 0-.412 1.215v3.088a.257.257 0 0 1-.078.19.24.24 0 0 1-.178.067zm8.846.112a2.466 2.466 0 0 1-1.84-.7 2.938 2.938 0 0 1-.747-1.94l-.011-.379.011-.368a2.953 2.953 0 0 1 .758-1.918 2.7 2.7 0 0 1 3.735.078 3.114 3.114 0 0 1 .68 2.119v.19a.257.257 0 0 1-.078.189.241.241 0 0 1-.178.067h-3.858v.1a2.11 2.11 0 0 0 .435 1.238 1.332 1.332 0 0 0 1.081.5 1.563 1.563 0 0 0 .836-.2 1.7 1.7 0 0 0 .491-.435.6.6 0 0 1 .145-.156.391.391 0 0 1 .19-.033h.547a.252.252 0 0 1 .167.056.192.192 0 0 1 .067.156.975.975 0 0 1-.312.591 2.51 2.51 0 0 1-.859.6 3.049 3.049 0 0 1-1.26.248zm1.527-3.434v-.033a1.817 1.817 0 0 0-.424-1.249 1.512 1.512 0 0 0-2.23 0 1.883 1.883 0 0 0-.4 1.249v.033z" fill="#51504f" data-name="Path 9" transform="translate(-1460.834 -808.144)"></path> |
| <path id="Path_10" d="M1527.2 827.081l-.061.061zm-.056-.279l-.08-.031zm2.766-7.214l.08.031zm1.472 0l-.081.029zm2.754 7.214l.084-.015a.064.064 0 0 0 0-.015zm.022.123h.086v-.015zm-.067.156l.06.061zm-.914.011l-.061.061.006.005zm-.089-.134l.081-.027zm-.613-1.583l.08-.031a.086.086 0 0 0-.08-.055zm-3.657 0v-.086a.086.086 0 0 0-.08.055zm-.613 1.583l-.08-.031zm-.1.134l.055.066zm4.047-2.676v.086a.086.086 0 0 0 .08-.116zm-1.505-3.958l.08-.03a.086.086 0 0 0-.16 0zm-1.505 3.958l-.08-.03a.086.086 0 0 0 .08.116zm-1.784 2.646a.128.128 0 0 1-.1-.042l-.122.121a.3.3 0 0 0 .217.092zm-.1-.042a.129.129 0 0 1-.042-.1h-.171a.3.3 0 0 0 .092.217zm-.042-.1a.38.38 0 0 1 .007-.1l-.163-.054a.514.514 0 0 0-.016.15zm.005-.092l2.765-7.214-.16-.061-2.765 7.214zm2.766-7.216a.283.283 0 0 1 .1-.143.3.3 0 0 1 .174-.046v-.172a.47.47 0 0 0-.271.076.453.453 0 0 0-.166.226zm.276-.189h.758v-.172h-.758zm.758 0a.3.3 0 0 1 .175.046.283.283 0 0 1 .1.143l.161-.059a.451.451 0 0 0-.166-.226.47.47 0 0 0-.272-.076zm.277.19l2.754 7.214.16-.061-2.754-7.214zm2.75 7.2l.022.123.169-.031-.022-.123zm.021.107a.13.13 0 0 1-.042.1l.121.121a.3.3 0 0 0 .092-.217zm-.042.1a.13.13 0 0 1-.1.042v.171a.3.3 0 0 0 .217-.092zm-.1.042h-.568v.171h.568zm-.568 0a.206.206 0 0 1-.135-.036l-.11.132a.373.373 0 0 0 .245.076zm-.129-.031a.262.262 0 0 1-.069-.1l-.162.054a.431.431 0 0 0 .11.167zm-.07-.1l-.613-1.584-.16.062.613 1.583zm-.693-1.638h-3.657v.171h3.657zm-3.737.055l-.614 1.584.16.062.613-1.583zm-.615 1.587a.235.235 0 0 1-.075.1l.111.13a.4.4 0 0 0 .126-.172zm-.074.1a.185.185 0 0 1-.124.036v.171a.354.354 0 0 0 .233-.076zm-.124.036h-.569v.171h.569zm4.306-2.677l-1.505-3.958-.16.061 1.505 3.958zm-1.666-3.958l-1.505 3.958.16.061 1.505-3.958zm-1.425 4.075h3.01v-.171h-3.01zm6.143 4.687l-.06.061zm0-7.761l.061.061zm.881 0l-.065.056.01.009zm.078.669h-.086a.086.086 0 0 0 .155.051zm3.579-.123l-.067.053zm.636 1.9h-.086zm0 .758l-.085-.007zm-.636 1.9l.067.054zm-3.557-.1l.068-.052a.086.086 0 0 0-.154.052zm-.067 2.765l-.061-.06zm2.787-3.323l-.069-.051zm.4-1.293l-.085-.008v.005zm-2.709-1.918l-.068-.052zm-.413 1.2h-.086zm-.011.423h-.085zm.011.435h-.086zm.424 1.149l.066-.054zm-1.216 3.315a.173.173 0 0 1-.129-.053l-.121.121a.342.342 0 0 0 .25.1zm-.129-.053a.157.157 0 0 1-.042-.118h-.172a.325.325 0 0 0 .092.239zm-.042-.118v-7.4h-.172v7.4zm0-7.4a.157.157 0 0 1 .042-.118l-.121-.121a.324.324 0 0 0-.092.239zm.042-.118a.173.173 0 0 1 .129-.053v-.172a.342.342 0 0 0-.25.1zm.129-.053h.513v-.172h-.513zm.513 0a.137.137 0 0 1 .113.048l.13-.111a.309.309 0 0 0-.244-.108zm.123.058a.137.137 0 0 1 .048.113h.171a.309.309 0 0 0-.108-.243zm.048.113v.49h.171v-.49zm.155.541a2.033 2.033 0 0 1 1.759-.823v-.171a2.2 2.2 0 0 0-1.9.894zm1.759-.823a2.007 2.007 0 0 1 1.683.7l.135-.106a2.177 2.177 0 0 0-1.818-.768zm1.683.7a3.045 3.045 0 0 1 .617 1.845l.171-.007a3.218 3.218 0 0 0-.654-1.946zm.617 1.85c.007.078.011.2.011.372h.171c0-.171 0-.3-.012-.387zm.011.372c0 .171 0 .294-.011.372l.17.015c.008-.086.012-.216.012-.387zm-.011.376a3.08 3.08 0 0 1-.617 1.846l.134.106a3.25 3.25 0 0 0 .654-1.945zm-.617 1.845a2.025 2.025 0 0 1-1.683.7v.171a2.2 2.2 0 0 0 1.817-.768zm-1.683.7a2.068 2.068 0 0 1-1.739-.8l-.136.1a2.239 2.239 0 0 0 1.874.87zm-1.892-.75v2.587h.172v-2.587zm0 2.587a.156.156 0 0 1-.042.118l.121.121a.325.325 0 0 0 .092-.239zm-.046.123a.138.138 0 0 1-.114.048v.172a.308.308 0 0 0 .244-.108zm-.114.048h-.546v.172h.546zm1.817-2.739a1.408 1.408 0 0 0 1.218-.526l-.138-.1a1.24 1.24 0 0 1-1.079.455zm1.217-.525a2.355 2.355 0 0 0 .419-1.341l-.171-.007a2.182 2.182 0 0 1-.385 1.246zm.418-1.336c.008-.079.012-.19.012-.332h-.172c0 .14 0 .245-.011.315zm.012-.332a2.726 2.726 0 0 0-.407-1.632 1.448 1.448 0 0 0-1.24-.562v.171a1.278 1.278 0 0 1 1.1.492 2.565 2.565 0 0 1 .374 1.53zm-1.647-2.193a1.452 1.452 0 0 0-1.228.547l.136.1a1.282 1.282 0 0 1 1.091-.479zm-1.228.547a2.2 2.2 0 0 0-.43 1.252l.172.008a2.028 2.028 0 0 1 .4-1.157zm-.43 1.254l-.011.424h.171l.011-.424zm-.011.428l.011.435h.172l-.011-.435zm.011.436a1.95 1.95 0 0 0 .443 1.2l.133-.109a1.776 1.776 0 0 1-.4-1.1zm.443 1.2a1.484 1.484 0 0 0 1.214.522v-.171a1.314 1.314 0 0 1-1.082-.459zm5.828 1.117l.037-.077zm-.747-.6l-.07.049zm.335-2.063l.052.068zm1.65-.624l.012.085zm1.661-.234l.012.085a.086.086 0 0 0 .074-.085zm-2.107-1.249l.046.072zm-.468.48l-.075-.042a.083.083 0 0 0-.006.015zm-.089.145l-.054-.067-.007.006zm-.792-.022l-.065.056.009.009zm-.067-.178h-.086zm.245-.6l-.07-.049zm.747-.591l.038.077zm3.033.334l-.063.058zm.468 5.252l.06.061zm-.881 0l-.065.056a.043.043 0 0 0 .009.009zm-.067-.669h.086a.086.086 0 0 0-.156-.048zm-.714.6l-.04-.076zm.223-1.059l-.062-.06zm.468-1.684h.086a.086.086 0 0 0-.1-.085zm-1.293.189l.012.085zm-1.193.379l.046.072zm-.033 1.349l-.047.071zm.635.985a2.241 2.241 0 0 1-.978-.215l-.074.155a2.412 2.412 0 0 0 1.051.231zm-.978-.215a1.859 1.859 0 0 1-.715-.576l-.138.1a2.024 2.024 0 0 0 .779.629zm-.713-.573a1.4 1.4 0 0 1-.253-.81h-.172a1.571 1.571 0 0 0 .283.907zm-.253-.81a1.374 1.374 0 0 1 .569-1.136l-.105-.135a1.544 1.544 0 0 0-.635 1.272zm.569-1.137a3.316 3.316 0 0 1 1.609-.607l-.024-.17a3.481 3.481 0 0 0-1.691.642zm1.609-.607l1.661-.234-.024-.17-1.662.234zm1.735-.319v-.323h-.171v.323zm0-.323a1.156 1.156 0 0 0-.355-.917 1.536 1.536 0 0 0-1.035-.306v.172a1.37 1.37 0 0 1 .922.263.986.986 0 0 1 .3.788zm-1.39-1.223a1.486 1.486 0 0 0-.851.227l.1.142a1.316 1.316 0 0 1 .755-.2zm-.849.226a1.452 1.452 0 0 0-.5.51l.15.084a1.286 1.286 0 0 1 .44-.449zm-.5.524a.226.226 0 0 1-.062.105l.107.134a.391.391 0 0 0 .117-.185zm-.068.112a.1.1 0 0 1-.073.019v.171a.266.266 0 0 0 .194-.07zm-.073.019h-.48v.171h.48zm-.48 0a.18.18 0 0 1-.122-.046l-.112.13a.352.352 0 0 0 .234.087zm-.113-.037a.18.18 0 0 1-.047-.123h-.171a.352.352 0 0 0 .087.234zm-.047-.119a1.1 1.1 0 0 1 .23-.557l-.14-.1a1.253 1.253 0 0 0-.261.648zm.23-.556a1.843 1.843 0 0 1 .715-.564l-.075-.154a2.018 2.018 0 0 0-.78.618zm.716-.564a2.611 2.611 0 0 1 1.2-.247v-.171a2.781 2.781 0 0 0-1.277.266zm1.2-.247a2.268 2.268 0 0 1 1.732.563l.126-.116a2.435 2.435 0 0 0-1.858-.618zm1.733.564a1.945 1.945 0 0 1 .523 1.391h.171a2.117 2.117 0 0 0-.57-1.508zm.523 1.391v3.613h.171v-3.613zm0 3.613a.172.172 0 0 1-.053.129l.121.121a.344.344 0 0 0 .1-.25zm-.053.129a.157.157 0 0 1-.118.042v.171a.326.326 0 0 0 .239-.092zm-.118.042h-.513v.171h.513zm-.513 0a.2.2 0 0 1-.134-.046l-.111.13a.367.367 0 0 0 .245.088zm-.124-.037a.194.194 0 0 1-.047-.134h-.171a.366.366 0 0 0 .087.245zm-.047-.134v-.479h-.171v.479zm-.156-.528a1.846 1.846 0 0 1-.683.575l.079.152a2.012 2.012 0 0 0 .745-.629zm-.683.575a2.476 2.476 0 0 1-1.153.236v.171a2.644 2.644 0 0 0 1.233-.255zm-.919-.429a1.666 1.666 0 0 0 1.244-.494l-.123-.12a1.493 1.493 0 0 1-1.121.442zm1.244-.494a1.969 1.969 0 0 0 .492-1.431h-.171a1.8 1.8 0 0 1-.444 1.312zm.492-1.431v-.312h-.171v.312zm-.1-.4l-1.293.189.025.17 1.293-.189zm-1.293.189a3 3 0 0 0-1.228.393l.095.143a2.837 2.837 0 0 1 1.158-.365zm-1.227.392a.845.845 0 0 0-.441.73h.172a.676.676 0 0 1 .362-.586zm-.441.73a.869.869 0 0 0 .406.762l.095-.142a.7.7 0 0 1-.33-.62zm.408.764a1.673 1.673 0 0 0 .916.247v-.171a1.5 1.5 0 0 1-.823-.221zm5.686.329l-.061.06zm-.714-1.9h-.085zm-.011-.446h-.085zm.011-.446h-.085zm.714-1.885l.061.061zm3.234-.39l-.04.076zm.825.713l-.073.046zm.3.848h-.086zm-.067.178l.056.065zm-.892.022l.054-.067zm-.112-.178l-.081.029zm-.535-.758l-.048.071zm-1.974.2l-.062-.059zm-.435 1.3h-.086zm-.011.4h-.086zm.011.379h-.086zm.435 1.316l-.062.059zm1.974.2l.046.072zm.535-.769l-.079-.033zm.112-.178l.054.067.007-.006zm.892.022l-.061.06zm.067.178l-.085-.009zm-.3.847l-.072-.046zm-.825.714l-.04-.076zm-1.36.2a2.471 2.471 0 0 1-1.814-.644l-.12.122a2.64 2.64 0 0 0 1.933.694zm-1.813-.643a2.653 2.653 0 0 1-.689-1.839l-.171.006a2.822 2.822 0 0 0 .738 1.952zm-.689-1.838l-.011-.446h-.171l.011.446zm-.011-.442l.011-.446h-.171l-.011.446zm.011-.445a2.611 2.611 0 0 1 .689-1.827l-.122-.121a2.78 2.78 0 0 0-.738 1.942zm.689-1.827a2.447 2.447 0 0 1 1.813-.655v-.171a2.617 2.617 0 0 0-1.934.705zm1.813-.655a2.836 2.836 0 0 1 1.32.28l.079-.152a3 3 0 0 0-1.4-.3zm1.32.28a1.99 1.99 0 0 1 .792.683l.145-.091a2.158 2.158 0 0 0-.858-.744zm.793.685a1.617 1.617 0 0 1 .287.8l.171-.009a1.789 1.789 0 0 0-.315-.89zm.287.809a.11.11 0 0 1-.037.1l.112.13a.281.281 0 0 0 .1-.252zm-.037.1a.2.2 0 0 1-.134.046v.171a.369.369 0 0 0 .246-.088zm-.134.046h-.535v.171h.535zm-.535 0a.184.184 0 0 1-.114-.026l-.107.134a.345.345 0 0 0 .221.064zm-.114-.026a.389.389 0 0 1-.086-.144l-.158.066a.533.533 0 0 0 .137.212zm-.084-.14a1.514 1.514 0 0 0-.57-.8l-.093.144a1.343 1.343 0 0 1 .5.715zm-.568-.8a1.6 1.6 0 0 0-.918-.249v.171a1.435 1.435 0 0 1 .822.219zm-.918-.249a1.535 1.535 0 0 0-1.166.462l.124.118a1.364 1.364 0 0 1 1.042-.408zm-1.166.462a2.036 2.036 0 0 0-.458 1.36l.171.006a1.872 1.872 0 0 1 .411-1.249zm-.458 1.361l-.011.4h.171l.011-.4zm-.011.406l.011.379.171-.005-.011-.379zm.011.38a2.052 2.052 0 0 0 .458 1.371l.124-.118a1.889 1.889 0 0 1-.411-1.26zm.458 1.371a1.533 1.533 0 0 0 1.166.451v-.172a1.363 1.363 0 0 1-1.042-.4zm1.166.451a1.661 1.661 0 0 0 .916-.237l-.093-.144a1.491 1.491 0 0 1-.823.209zm.918-.238a1.576 1.576 0 0 0 .568-.812l-.162-.057a1.409 1.409 0 0 1-.5.727zm.566-.807a.39.39 0 0 1 .086-.144l-.107-.134a.533.533 0 0 0-.137.213zm.093-.151a.144.144 0 0 1 .107-.031v-.171a.31.31 0 0 0-.228.081zm.107-.031h.535v-.171h-.535zm.535 0a.173.173 0 0 1 .129.053l.121-.121a.344.344 0 0 0-.25-.1zm.134.057a.11.11 0 0 1 .037.1l.17.017a.281.281 0 0 0-.1-.252zm.037.109a1.664 1.664 0 0 1-.288.806l.144.092a1.839 1.839 0 0 0 .315-.889zm-.288.806a1.989 1.989 0 0 1-.792.683l.079.152a2.162 2.162 0 0 0 .858-.744zm-.793.684a2.8 2.8 0 0 1-1.32.28v.171a2.96 2.96 0 0 0 1.4-.3zm2.568.187l-.065.056.01.009zm0-7.772l.061.06zm.926 0l-.065.056.009.009zm.078 2.776h-.085a.086.086 0 0 0 .153.053zm.758-.624l.038.077zm2.743.468l-.065.056zm.524 5.151l-.061-.06zm-.925 0l-.065.056.009.009zm-.457-4.5l-.065.056zm-2.23.011l-.062-.059zm-.49 4.493l-.061-.06zm-.736-.019a.2.2 0 0 1-.134-.046l-.112.13a.367.367 0 0 0 .245.088zm-.124-.037a.2.2 0 0 1-.046-.134h-.172a.367.367 0 0 0 .087.245zm-.046-.134v-7.4h-.172v7.4zm0-7.4a.156.156 0 0 1 .042-.118l-.121-.121a.326.326 0 0 0-.092.239zm.042-.118a.172.172 0 0 1 .129-.053v-.171a.343.343 0 0 0-.25.1zm.129-.053h.557v-.171h-.557zm.557 0a.137.137 0 0 1 .113.048l.13-.112a.308.308 0 0 0-.244-.108zm.122.057a.137.137 0 0 1 .048.113h.172a.309.309 0 0 0-.108-.243zm.048.113v2.6h.172v-2.6zm.153 2.651a2.076 2.076 0 0 1 .728-.6l-.075-.154a2.248 2.248 0 0 0-.788.649zm.73-.6a2.272 2.272 0 0 1 1.043-.214v-.171a2.438 2.438 0 0 0-1.121.232zm1.043-.214a1.982 1.982 0 0 1 1.6.661l.13-.112a2.152 2.152 0 0 0-1.727-.721zm1.6.663a2.557 2.557 0 0 1 .581 1.761h.171a2.727 2.727 0 0 0-.624-1.874zm.581 1.761v3.144h.171v-3.144zm0 3.144a.173.173 0 0 1-.053.129l.121.121a.345.345 0 0 0 .1-.25zm-.053.129a.156.156 0 0 1-.118.042v.171a.327.327 0 0 0 .239-.092zm-.118.042h-.557v.171h.557zm-.557 0a.2.2 0 0 1-.134-.046l-.112.13a.367.367 0 0 0 .245.088zm-.124-.037a.2.2 0 0 1-.046-.134h-.172a.368.368 0 0 0 .087.245zm-.046-.134V823.8h-.172v3.088zm0-3.088a1.859 1.859 0 0 0-.412-1.284l-.128.114a1.69 1.69 0 0 1 .368 1.169zm-.411-1.283a1.471 1.471 0 0 0-1.169-.464v.171a1.3 1.3 0 0 1 1.039.406zm-1.169-.464a1.566 1.566 0 0 0-1.188.473l.124.118a1.4 1.4 0 0 1 1.064-.419zm-1.188.473a1.779 1.779 0 0 0-.436 1.275h.172a1.609 1.609 0 0 1 .389-1.156zm-.436 1.275v3.088h.172V823.8zm0 3.088a.172.172 0 0 1-.053.129l.121.121a.344.344 0 0 0 .1-.25zm-.053.129a.156.156 0 0 1-.118.042v.171a.327.327 0 0 0 .239-.092zm-.118.042h-.557v.171h.557zm6.449-.505l-.062.059zm-.747-1.94h-.086zm-.012-.379h-.085v.005zm.012-.368l-.086-.006zm.758-1.918l-.061-.06zm3.735.078l-.065.056zm.6 2.5l.061.061zm-4.036.067v-.086a.086.086 0 0 0-.086.086zm0 .1h-.086zm.435 1.238l-.068.053zm1.918.3l.045.073zm.491-.435l-.069-.051zm.145-.156l.039.077h.006zm.9.022l-.055.066zm-.245.747l-.064-.057zm-.858.6l.035.078zm.267-3.189v.086a.086.086 0 0 0 .086-.086zm-.424-1.282l-.066.055zm-2.23 0l-.065-.055zm-.4 1.282h-.086a.086.086 0 0 0 .086.086zm1.528 3.349a2.38 2.38 0 0 1-1.779-.677l-.122.12a2.55 2.55 0 0 0 1.9.728zm-1.778-.676a2.86 2.86 0 0 1-.724-1.886l-.171.009a3.027 3.027 0 0 0 .771 1.995zm-.723-1.884l-.011-.379h-.171l.011.379zm-.011-.374l.011-.368-.172-.005-.011.368zm.011-.365a2.871 2.871 0 0 1 .735-1.864l-.124-.118a3.042 3.042 0 0 0-.782 1.971zm.734-1.864a2.331 2.331 0 0 1 1.756-.687v-.171a2.5 2.5 0 0 0-1.879.74zm1.756-.687a2.307 2.307 0 0 1 1.853.762l.13-.112a2.477 2.477 0 0 0-1.983-.821zm1.854.762a3.03 3.03 0 0 1 .659 2.062h.172a3.2 3.2 0 0 0-.7-2.175zm.659 2.062v.19h.172v-.19zm0 .19a.172.172 0 0 1-.053.129l.121.121a.345.345 0 0 0 .1-.25zm-.053.129a.156.156 0 0 1-.118.042v.171a.327.327 0 0 0 .239-.092zm-.118.042h-3.858v.171h3.858zm-3.944.086v.1h.172v-.1zm0 .1a2.2 2.2 0 0 0 .453 1.287l.135-.106a2.027 2.027 0 0 1-.417-1.189zm.454 1.288a1.418 1.418 0 0 0 1.148.533v-.171a1.247 1.247 0 0 1-1.015-.47zm1.148.533a1.647 1.647 0 0 0 .882-.214l-.09-.146a1.481 1.481 0 0 1-.791.188zm.882-.214a1.777 1.777 0 0 0 .515-.458l-.14-.1a1.613 1.613 0 0 1-.466.412zm.513-.456a1.251 1.251 0 0 1 .081-.1.28.28 0 0 1 .026-.025l.008-.006-.077-.153a.326.326 0 0 0-.083.068 1.55 1.55 0 0 0-.092.113zm.12-.134a.328.328 0 0 1 .146-.021v-.171a.468.468 0 0 0-.234.046zm.146-.021h.547v-.171h-.547zm.547 0a.166.166 0 0 1 .112.036l.11-.132a.337.337 0 0 0-.222-.076zm.112.036a.107.107 0 0 1 .036.09h.171a.277.277 0 0 0-.1-.222zm.036.09a.9.9 0 0 1-.291.534l.128.115a1.055 1.055 0 0 0 .334-.649zm-.291.535a2.42 2.42 0 0 1-.83.581l.072.156a2.6 2.6 0 0 0 .888-.624zm-.829.58a2.964 2.964 0 0 1-1.224.238v.171a3.133 3.133 0 0 0 1.295-.253zm.389-3.111v-.033h-.171v.033zm0-.033a1.9 1.9 0 0 0-.445-1.306l-.129.114a1.731 1.731 0 0 1 .4 1.192zm-.444-1.3a1.466 1.466 0 0 0-1.181-.521v.172a1.3 1.3 0 0 1 1.049.46zm-1.181-.521a1.466 1.466 0 0 0-1.18.521l.131.11a1.3 1.3 0 0 1 1.049-.46zm-1.181.521a1.965 1.965 0 0 0-.422 1.3h.172a1.794 1.794 0 0 1 .382-1.194zm-.422 1.3v.033h.172v-.033zm.086.119h3.055v-.171h-3.055z" fill="#51504f" data-name="Path 10" transform="translate(-1460.636 -807.945)"></path> |
| <path id="Path_11" d="M1519.066 884.011a.581.581 0 0 1-.567-.567 1.151 1.151 0 0 1 .028-.312l7.026-18.328a.881.881 0 0 1 .906-.623h1.926a.882.882 0 0 1 .907.623l7 18.328.057.312a.583.583 0 0 1-.567.567h-1.445a.735.735 0 0 1-.482-.142.9.9 0 0 1-.226-.34l-1.558-4.023h-9.292l-1.558 4.023a.8.8 0 0 1-.255.34.688.688 0 0 1-.453.142zm12.181-6.94l-3.824-10.056-3.823 10.055zm8.184-10.538a.592.592 0 0 1-.652-.651v-1.53a.714.714 0 0 1 .17-.482.656.656 0 0 1 .482-.2h1.785a.677.677 0 0 1 .68.68v1.53a.655.655 0 0 1-.2.481.713.713 0 0 1-.481.17zm.227 17.479a.593.593 0 0 1-.652-.652v-13.428a.611.611 0 0 1 .17-.453.656.656 0 0 1 .482-.2h1.359a.679.679 0 0 1 .652.651v13.427a.655.655 0 0 1-.2.482.613.613 0 0 1-.453.17zm6.861 0a.592.592 0 0 1-.651-.652v-13.4a.715.715 0 0 1 .17-.481.656.656 0 0 1 .482-.2h1.3a.677.677 0 0 1 .68.68v1.246a4.255 4.255 0 0 1 3.966-1.926h1.1a.679.679 0 0 1 .651.651v1.161a.566.566 0 0 1-.2.453.612.612 0 0 1-.453.17h-1.7a3.2 3.2 0 0 0-2.408.907 3.253 3.253 0 0 0-.879 2.408v8.328a.656.656 0 0 1-.2.482.716.716 0 0 1-.482.17zm12.234 0a.593.593 0 0 1-.651-.652v-11.814h-2.408a.592.592 0 0 1-.651-.651v-.963a.611.611 0 0 1 .17-.453.654.654 0 0 1 .481-.2h2.408v-1.417q0-4.816 4.872-4.815h1.586a.679.679 0 0 1 .652.651v.963a.656.656 0 0 1-.2.481.613.613 0 0 1-.453.17h-1.529a2.1 2.1 0 0 0-1.785.68 3.248 3.248 0 0 0-.51 2.011v1.275h6.062V863.7a.613.613 0 0 1 .17-.453.656.656 0 0 1 .482-.2h1.3a.679.679 0 0 1 .652.651v19.659a.655.655 0 0 1-.2.482.613.613 0 0 1-.454.17h-1.3a.592.592 0 0 1-.652-.652v-11.811h-6.062v11.813a.657.657 0 0 1-.2.482.614.614 0 0 1-.454.17zm20.9.283a6.487 6.487 0 0 1-4.844-1.757 6.837 6.837 0 0 1-1.813-4.674l-.029-1.218.029-1.218a6.732 6.732 0 0 1 1.841-4.646 7.389 7.389 0 0 1 9.631 0 6.736 6.736 0 0 1 1.841 4.646q.028.311.028 1.218t-.028 1.218a6.772 6.772 0 0 1-1.841 4.674 6.391 6.391 0 0 1-4.82 1.756zm0-2.181a3.582 3.582 0 0 0 2.8-1.133 4.931 4.931 0 0 0 1.133-3.258q.028-.283.028-1.076t-.028-1.076a4.931 4.931 0 0 0-1.133-3.258 3.582 3.582 0 0 0-2.8-1.133 3.671 3.671 0 0 0-2.833 1.133 4.83 4.83 0 0 0-1.1 3.258l-.028 1.076.028 1.076a4.83 4.83 0 0 0 1.1 3.258 3.671 3.671 0 0 0 2.828 1.132zm13.755 1.9a.846.846 0 0 1-.566-.17 1.321 1.321 0 0 1-.34-.538l-4.023-13.144-.056-.283a.575.575 0 0 1 .17-.425.641.641 0 0 1 .425-.17h1.246a.612.612 0 0 1 .453.17.646.646 0 0 1 .255.312l3.145 10.679 3.371-10.566a.761.761 0 0 1 .255-.4.726.726 0 0 1 .538-.2h.963a.728.728 0 0 1 .539.2.76.76 0 0 1 .255.4l3.371 10.566 3.144-10.679a.655.655 0 0 1 .2-.312.714.714 0 0 1 .482-.17h1.275a.542.542 0 0 1 .4.17.576.576 0 0 1 .17.425l-.057.283-3.994 13.144a1.323 1.323 0 0 1-.34.538.9.9 0 0 1-.6.17h-1.1a.86.86 0 0 1-.935-.708l-3.286-10.141-3.286 10.141a.928.928 0 0 1-.963.708z" fill="#51504f" data-name="Path 11" transform="translate(-1454.66 -838.62)"></path> |
| </g> |
| </g> |
| </g> |
| </svg> |
| |
| </a> |
| </div> |
| <div class="desktop-only navbar__menu-container"> |
| |
| <div class="navbar__menu-content" id="main_navbar"> |
| |
| <div class="navbar__links-container"> |
| |
| <a class="navbar__text-link" href="/community/"> |
| Community |
| </a> |
| |
| <a class="navbar__text-link" href="/meetups/"> |
| Meetups |
| </a> |
| |
| <a class="navbar__text-link" href="/docs/"> |
| Documentation |
| </a> |
| |
| <a class="navbar__text-link" href="/use-cases/"> |
| Use-cases |
| </a> |
| |
| <a class="navbar__text-link" href="/announcements/"> |
| Announcements |
| </a> |
| |
| <a class="navbar__text-link" href="/blog/"> |
| Blog |
| </a> |
| |
| <a class="navbar__text-link" href="/ecosystem/"> |
| Ecosystem |
| </a> |
| |
| </div> |
| |
| |
| |
| </div> |
| |
| </div> |
| <div class="mobile-only navbar__drawer-container"> |
| <button class="navbar__toggle-button" id="navbar-toggle-button"> |
| |
| <div id="hamburger-icon" class="navbar__toggle-button--icon visible"> |
| <svg xmlns="http://www.w3.org/2000/svg" width="26" height="20" viewBox="0 0 26 20"> |
| <g id="Group_1294" data-name="Group 1294" transform="translate(-38.791 291)"> |
| <g id="Group_1291" data-name="Group 1291" transform="translate(39 -291)"> |
| <rect id="Rectangle_461" width="26" height="2" fill="#51504f" data-name="Rectangle 461" rx="1" transform="translate(-.209)"></rect> |
| </g> |
| <g id="Group_1292" data-name="Group 1292" transform="translate(39 -281.822)"> |
| <rect id="Rectangle_462" width="26" height="2" fill="#51504f" data-name="Rectangle 462" rx="1" transform="translate(-.209 -.178)"></rect> |
| </g> |
| <g id="Group_1293" data-name="Group 1293" transform="translate(39 -272.644)"> |
| <rect id="Rectangle_463" width="26" height="2" fill="#51504f" data-name="Rectangle 463" rx="1" transform="translate(-.209 -.356)"></rect> |
| </g> |
| </g> |
| </svg> |
| |
| </div> |
| |
| <div id="close-icon" class="navbar__toggle-button--icon"> |
| <svg xmlns="http://www.w3.org/2000/svg" width="19.799" height="19.799" viewBox="0 0 19.799 19.799"> |
| <g id="Group_1574" data-name="Group 1574" transform="translate(-41.892 290.899)"> |
| <g id="Group_1291" data-name="Group 1291" transform="rotate(-45 -308.114 -187.077)"> |
| <rect id="Rectangle_461" width="26" height="2" fill="#51504f" data-name="Rectangle 461" rx="1" transform="translate(-.209)"></rect> |
| </g> |
| <g id="Group_1292" data-name="Group 1292" transform="rotate(45 372.48 -93.011)"> |
| <rect id="Rectangle_462" width="26" height="2" fill="#51504f" data-name="Rectangle 462" rx="1" transform="translate(-.209 -.178)"></rect> |
| </g> |
| </g> |
| </svg> |
| |
| </div> |
| |
| </button> |
| <div class="navbar__drawer" id="navbar-drawer"> |
| <div class="navbar__menu-content" id="main_navbar"> |
| |
| <div class="navbar__links-container"> |
| |
| <a class="navbar__text-link" href="/community/"> |
| Community |
| </a> |
| |
| <a class="navbar__text-link" href="/meetups/"> |
| Meetups |
| </a> |
| |
| <a class="navbar__text-link" href="/docs/"> |
| Documentation |
| </a> |
| |
| <a class="navbar__text-link" href="/use-cases/"> |
| Use-cases |
| </a> |
| |
| <a class="navbar__text-link" href="/announcements/"> |
| Announcements |
| </a> |
| |
| <a class="navbar__text-link" href="/blog/"> |
| Blog |
| </a> |
| |
| <a class="navbar__text-link" href="/ecosystem/"> |
| Ecosystem |
| </a> |
| |
| |
| </div> |
| |
| |
| </div> |
| </div> |
| </div> |
| </nav> |
| |
| </header> |
| |
| |
| <div class="roadmap container-fluid td-default base-layout"> |
| |
| |
| <div class="content-drawer-wrapper"> |
| <button class="content-drawer__toggle-button" id="content-open-button"> |
| |
| <div id="hamburger-icon" class="content-drawer__toggle-button--icon visible"> |
| <svg xmlns="http://www.w3.org/2000/svg" width="20.005" height="13.879" viewBox="0 0 20.005 13.879"> |
| <g id="Group_1619" data-name="Group 1619" transform="translate(271.132 -418.872)"> |
| <g id="Group_1613" data-name="Group 1613" transform="translate(-266.229 431.045)"> |
| <path id="Path_1337" d="M-218.5 513.215h-14.583a.259.259 0 0 1-.259-.26.259.259 0 0 1 .259-.259h14.583a.26.26 0 0 1 .259.259.259.259 0 0 1-.259.26z" fill="#51504f" data-name="Path 1337" transform="translate(233.345 -512.696)"></path> |
| </g> |
| <g id="Group_1614" data-name="Group 1614" transform="translate(-266.229 425.684)"> |
| <path id="Path_1338" d="M-218.5 471.9h-14.583a.259.259 0 0 1-.259-.26.26.26 0 0 1 .259-.259h14.583a.26.26 0 0 1 .259.259.26.26 0 0 1-.259.26z" fill="#51504f" data-name="Path 1338" transform="translate(233.345 -471.376)"></path> |
| </g> |
| <g id="Group_1615" data-name="Group 1615" transform="translate(-266.229 420.323)"> |
| <path id="Path_1339" d="M-218.5 430.574h-14.583a.259.259 0 0 1-.259-.259.259.259 0 0 1 .259-.259h14.583a.26.26 0 0 1 .259.259.259.259 0 0 1-.259.259z" fill="#51504f" data-name="Path 1339" transform="translate(233.345 -430.055)"></path> |
| </g> |
| <g id="Group_1616" data-name="Group 1616" transform="translate(-271.132 429.814)"> |
| <path id="Path_1340" d="M-269.663 506.145a1.47 1.47 0 0 1-1.469-1.469 1.47 1.47 0 0 1 1.469-1.469 1.47 1.47 0 0 1 1.469 1.469 1.47 1.47 0 0 1-1.469 1.469zm0-2.418a.951.951 0 0 0-.95.95.951.951 0 0 0 .95.95.951.951 0 0 0 .95-.95.951.951 0 0 0-.95-.95z" fill="#51504f" data-name="Path 1340" transform="translate(271.132 -503.208)"></path> |
| </g> |
| <g id="Group_1617" data-name="Group 1617" transform="translate(-271.132 424.556)"> |
| <path id="Path_1341" d="M-269.663 465.62a1.47 1.47 0 0 1-1.469-1.469 1.47 1.47 0 0 1 1.469-1.469 1.47 1.47 0 0 1 1.469 1.469 1.47 1.47 0 0 1-1.469 1.469zm0-2.418a.951.951 0 0 0-.95.95.951.951 0 0 0 .95.95.951.951 0 0 0 .95-.95.951.951 0 0 0-.95-.952z" fill="#51504f" data-name="Path 1341" transform="translate(271.132 -462.683)"></path> |
| </g> |
| <g id="Group_1618" data-name="Group 1618" transform="translate(-271.132 418.872)"> |
| <path id="Path_1342" d="M-269.663 421.809a1.47 1.47 0 0 1-1.469-1.469 1.47 1.47 0 0 1 1.469-1.469 1.47 1.47 0 0 1 1.469 1.469 1.47 1.47 0 0 1-1.469 1.469zm0-2.418a.951.951 0 0 0-.95.95.951.951 0 0 0 .95.95.951.951 0 0 0 .95-.95.951.951 0 0 0-.95-.95z" fill="#51504f" data-name="Path 1342" transform="translate(271.132 -418.872)"></path> |
| </g> |
| </g> |
| </svg> |
| |
| <span class="bodytext__mobile--brownish-grey">Content</span> |
| </div> |
| |
| </button> |
| <nav id="content-navbar" class="navbar navbar--hidden"> |
| <div class="navbar__icon-container"> |
| <a href="/"> |
| <svg xmlns="http://www.w3.org/2000/svg" width="155.314" height="60" viewBox="0 0 155.314 60"> |
| <defs> |
| <clipPath id="clip-path"> |
| <path id="Rectangle_1" d="M0 0h155.314v60H0z" fill="none" data-name="Rectangle 1"></path> |
| </clipPath> |
| </defs> |
| <g id="logo" transform="translate(-1305 -780.355)"> |
| <g id="Group_2" clip-path="url(#clip-path)" data-name="Group 2" transform="translate(1305 780.355)"> |
| <g id="Group_1" data-name="Group 1" transform="translate(.486 .486)"> |
| <path id="Path_1" d="M1307.562 880.867l28.187-28.893a.521.521 0 0 0 .063-.666c-1.714-2.393-4.877-2.808-6.049-4.416-3.472-4.763-4.353-7.459-5.845-7.292a.456.456 0 0 0-.271.143l-10.182 10.438c-5.858 6-6.7 19.225-6.852 30.3a.552.552 0 0 0 .949.386z" fill="#017cee" data-name="Path 1" transform="translate(-1306.613 -822.232)"></path> |
| <path id="Path_2" d="M1405.512 908.489l-28.893-28.189a.521.521 0 0 0-.667-.063c-2.393 1.715-2.808 4.877-4.416 6.049-4.763 3.472-7.459 4.353-7.292 5.845a.456.456 0 0 0 .143.27l10.438 10.182c6 5.858 19.225 6.7 30.3 6.852a.552.552 0 0 0 .387-.946z" fill="#00ad46" data-name="Path 2" transform="translate(-1346.876 -850.567)"></path> |
| <path id="Path_3" d="M1373.909 902.252c-3.28-3.2-4.8-9.53 1.486-22.583-10.219 4.567-13.8 10.57-12.039 12.289z" fill="#04d659" data-name="Path 3" transform="translate(-1345.96 -850.233)"></path> |
| <path id="Path_4" d="M1433.132 782.359l-28.186 28.893a.52.52 0 0 0-.063.666c1.715 2.393 4.876 2.808 6.049 4.416 3.472 4.763 4.354 7.459 5.845 7.292a.454.454 0 0 0 .271-.143l10.182-10.438c5.858-6 6.7-19.225 6.852-30.3a.553.553 0 0 0-.95-.386z" fill="#00c7d4" data-name="Path 4" transform="translate(-1375.21 -782.123)"></path> |
| <path id="Path_5" d="M1426.9 881.155c-3.2 3.28-9.53 4.8-22.584-1.486 4.567 10.219 10.57 13.8 12.289 12.039z" fill="#11e1ee" data-name="Path 5" transform="translate(-1374.875 -850.233)"></path> |
| <path id="Path_6" d="M1307 782.919l28.893 28.186a.521.521 0 0 0 .666.063c2.393-1.715 2.808-4.877 4.416-6.049 4.763-3.472 7.459-4.353 7.292-5.845a.459.459 0 0 0-.143-.271l-10.438-10.182c-6-5.858-19.225-6.7-30.3-6.852a.552.552 0 0 0-.386.95z" fill="#e43921" data-name="Path 6" transform="translate(-1306.766 -781.97)"></path> |
| <path id="Path_7" d="M1405.8 804.711c3.28 3.2 4.8 9.53-1.486 22.584 10.219-4.567 13.8-10.571 12.039-12.289z" fill-rule="evenodd" fill="#ff7557" data-name="Path 7" transform="translate(-1374.875 -797.859)"></path> |
| <path id="Path_8" d="M1329.355 849.266c3.2-3.28 9.53-4.8 22.584 1.486-4.567-10.219-10.57-13.8-12.289-12.039z" fill="#0cb6ff" data-name="Path 8" transform="translate(-1322.503 -821.316)"></path> |
| <circle id="Ellipse_1" cx="1.26" cy="1.26" r="1.26" fill="#4a4848" data-name="Ellipse 1" transform="translate(28.18 28.171)"></circle> |
| <path id="Path_9" d="M1527.558 827.347a.229.229 0 0 1-.223-.223.458.458 0 0 1 .011-.123l2.766-7.214a.346.346 0 0 1 .357-.245h.758a.348.348 0 0 1 .357.245l2.754 7.214.022.123a.228.228 0 0 1-.223.223h-.568a.288.288 0 0 1-.19-.056.352.352 0 0 1-.089-.134l-.613-1.583h-3.657l-.613 1.583a.317.317 0 0 1-.1.134.269.269 0 0 1-.178.056zm4.795-2.732l-1.505-3.958-1.505 3.958zm3.322 4.85a.258.258 0 0 1-.189-.078.241.241 0 0 1-.067-.178v-7.4a.241.241 0 0 1 .067-.178.258.258 0 0 1 .189-.078h.513a.268.268 0 0 1 .256.256v.49a2.118 2.118 0 0 1 1.828-.858 2.092 2.092 0 0 1 1.751.736 3.135 3.135 0 0 1 .636 1.9q.011.122.011.379t-.011.379a3.168 3.168 0 0 1-.636 1.9 2.111 2.111 0 0 1-1.751.736 2.154 2.154 0 0 1-1.806-.836v2.587a.241.241 0 0 1-.067.178.223.223 0 0 1-.179.078zm2.364-2.91a1.324 1.324 0 0 0 1.149-.491 2.266 2.266 0 0 0 .4-1.293q.011-.111.011-.323 0-2.107-1.562-2.107a1.365 1.365 0 0 0-1.159.513 2.111 2.111 0 0 0-.412 1.2l-.012.424.012.435a1.862 1.862 0 0 0 .424 1.149 1.4 1.4 0 0 0 1.148.493zm5.628.9a2.329 2.329 0 0 1-1.015-.223 1.94 1.94 0 0 1-.747-.6 1.487 1.487 0 0 1-.268-.859 1.459 1.459 0 0 1 .6-1.2 3.4 3.4 0 0 1 1.65-.624l1.661-.234v-.323q0-1.137-1.3-1.137a1.4 1.4 0 0 0-.8.212 1.376 1.376 0 0 0-.468.48.305.305 0 0 1-.089.145.18.18 0 0 1-.134.045h-.48a.23.23 0 0 1-.245-.245 1.17 1.17 0 0 1 .245-.6 1.931 1.931 0 0 1 .747-.591 2.7 2.7 0 0 1 1.238-.256 2.351 2.351 0 0 1 1.8.591 2.032 2.032 0 0 1 .547 1.45v3.613a.257.257 0 0 1-.078.19.24.24 0 0 1-.178.067h-.513a.233.233 0 0 1-.257-.256v-.479a1.923 1.923 0 0 1-.714.6 2.557 2.557 0 0 1-1.203.237zm.234-.836a1.579 1.579 0 0 0 1.182-.469 1.881 1.881 0 0 0 .468-1.371v-.312l-1.293.19a2.918 2.918 0 0 0-1.193.379.761.761 0 0 0-.4.658.784.784 0 0 0 .368.691 1.585 1.585 0 0 0 .867.237zm6.643.836a2.556 2.556 0 0 1-1.873-.669 2.738 2.738 0 0 1-.714-1.9l-.011-.446.011-.446a2.7 2.7 0 0 1 .714-1.885 2.531 2.531 0 0 1 1.873-.68 2.917 2.917 0 0 1 1.36.29 2.077 2.077 0 0 1 .825.714 1.7 1.7 0 0 1 .3.848.2.2 0 0 1-.067.178.281.281 0 0 1-.19.067h-.535a.265.265 0 0 1-.168-.045.458.458 0 0 1-.111-.178 1.428 1.428 0 0 0-.535-.758 1.516 1.516 0 0 0-.87-.234 1.45 1.45 0 0 0-1.1.435 1.952 1.952 0 0 0-.435 1.3l-.011.4.011.379a1.969 1.969 0 0 0 .435 1.316 1.446 1.446 0 0 0 1.1.424 1.577 1.577 0 0 0 .87-.223 1.493 1.493 0 0 0 .535-.769.458.458 0 0 1 .111-.178.228.228 0 0 1 .168-.056h.535a.258.258 0 0 1 .19.078.2.2 0 0 1 .067.178 1.75 1.75 0 0 1-.3.847 2.078 2.078 0 0 1-.825.714 2.876 2.876 0 0 1-1.361.302zm4.078-.112a.233.233 0 0 1-.257-.256v-7.4a.241.241 0 0 1 .067-.178.259.259 0 0 1 .19-.078h.557a.267.267 0 0 1 .257.256v2.6a2.167 2.167 0 0 1 .758-.624 2.353 2.353 0 0 1 1.082-.223 2.067 2.067 0 0 1 1.661.691 2.642 2.642 0 0 1 .6 1.818v3.144a.257.257 0 0 1-.078.19.24.24 0 0 1-.178.067h-.557a.233.233 0 0 1-.256-.256V824a1.775 1.775 0 0 0-.39-1.227 1.387 1.387 0 0 0-1.1-.435 1.481 1.481 0 0 0-1.126.446 1.7 1.7 0 0 0-.412 1.215v3.088a.257.257 0 0 1-.078.19.24.24 0 0 1-.178.067zm8.846.112a2.466 2.466 0 0 1-1.84-.7 2.938 2.938 0 0 1-.747-1.94l-.011-.379.011-.368a2.953 2.953 0 0 1 .758-1.918 2.7 2.7 0 0 1 3.735.078 3.114 3.114 0 0 1 .68 2.119v.19a.257.257 0 0 1-.078.189.241.241 0 0 1-.178.067h-3.858v.1a2.11 2.11 0 0 0 .435 1.238 1.332 1.332 0 0 0 1.081.5 1.563 1.563 0 0 0 .836-.2 1.7 1.7 0 0 0 .491-.435.6.6 0 0 1 .145-.156.391.391 0 0 1 .19-.033h.547a.252.252 0 0 1 .167.056.192.192 0 0 1 .067.156.975.975 0 0 1-.312.591 2.51 2.51 0 0 1-.859.6 3.049 3.049 0 0 1-1.26.248zm1.527-3.434v-.033a1.817 1.817 0 0 0-.424-1.249 1.512 1.512 0 0 0-2.23 0 1.883 1.883 0 0 0-.4 1.249v.033z" fill="#51504f" data-name="Path 9" transform="translate(-1460.834 -808.144)"></path> |
| <path id="Path_10" d="M1527.2 827.081l-.061.061zm-.056-.279l-.08-.031zm2.766-7.214l.08.031zm1.472 0l-.081.029zm2.754 7.214l.084-.015a.064.064 0 0 0 0-.015zm.022.123h.086v-.015zm-.067.156l.06.061zm-.914.011l-.061.061.006.005zm-.089-.134l.081-.027zm-.613-1.583l.08-.031a.086.086 0 0 0-.08-.055zm-3.657 0v-.086a.086.086 0 0 0-.08.055zm-.613 1.583l-.08-.031zm-.1.134l.055.066zm4.047-2.676v.086a.086.086 0 0 0 .08-.116zm-1.505-3.958l.08-.03a.086.086 0 0 0-.16 0zm-1.505 3.958l-.08-.03a.086.086 0 0 0 .08.116zm-1.784 2.646a.128.128 0 0 1-.1-.042l-.122.121a.3.3 0 0 0 .217.092zm-.1-.042a.129.129 0 0 1-.042-.1h-.171a.3.3 0 0 0 .092.217zm-.042-.1a.38.38 0 0 1 .007-.1l-.163-.054a.514.514 0 0 0-.016.15zm.005-.092l2.765-7.214-.16-.061-2.765 7.214zm2.766-7.216a.283.283 0 0 1 .1-.143.3.3 0 0 1 .174-.046v-.172a.47.47 0 0 0-.271.076.453.453 0 0 0-.166.226zm.276-.189h.758v-.172h-.758zm.758 0a.3.3 0 0 1 .175.046.283.283 0 0 1 .1.143l.161-.059a.451.451 0 0 0-.166-.226.47.47 0 0 0-.272-.076zm.277.19l2.754 7.214.16-.061-2.754-7.214zm2.75 7.2l.022.123.169-.031-.022-.123zm.021.107a.13.13 0 0 1-.042.1l.121.121a.3.3 0 0 0 .092-.217zm-.042.1a.13.13 0 0 1-.1.042v.171a.3.3 0 0 0 .217-.092zm-.1.042h-.568v.171h.568zm-.568 0a.206.206 0 0 1-.135-.036l-.11.132a.373.373 0 0 0 .245.076zm-.129-.031a.262.262 0 0 1-.069-.1l-.162.054a.431.431 0 0 0 .11.167zm-.07-.1l-.613-1.584-.16.062.613 1.583zm-.693-1.638h-3.657v.171h3.657zm-3.737.055l-.614 1.584.16.062.613-1.583zm-.615 1.587a.235.235 0 0 1-.075.1l.111.13a.4.4 0 0 0 .126-.172zm-.074.1a.185.185 0 0 1-.124.036v.171a.354.354 0 0 0 .233-.076zm-.124.036h-.569v.171h.569zm4.306-2.677l-1.505-3.958-.16.061 1.505 3.958zm-1.666-3.958l-1.505 3.958.16.061 1.505-3.958zm-1.425 4.075h3.01v-.171h-3.01zm6.143 4.687l-.06.061zm0-7.761l.061.061zm.881 0l-.065.056.01.009zm.078.669h-.086a.086.086 0 0 0 .155.051zm3.579-.123l-.067.053zm.636 1.9h-.086zm0 .758l-.085-.007zm-.636 1.9l.067.054zm-3.557-.1l.068-.052a.086.086 0 0 0-.154.052zm-.067 2.765l-.061-.06zm2.787-3.323l-.069-.051zm.4-1.293l-.085-.008v.005zm-2.709-1.918l-.068-.052zm-.413 1.2h-.086zm-.011.423h-.085zm.011.435h-.086zm.424 1.149l.066-.054zm-1.216 3.315a.173.173 0 0 1-.129-.053l-.121.121a.342.342 0 0 0 .25.1zm-.129-.053a.157.157 0 0 1-.042-.118h-.172a.325.325 0 0 0 .092.239zm-.042-.118v-7.4h-.172v7.4zm0-7.4a.157.157 0 0 1 .042-.118l-.121-.121a.324.324 0 0 0-.092.239zm.042-.118a.173.173 0 0 1 .129-.053v-.172a.342.342 0 0 0-.25.1zm.129-.053h.513v-.172h-.513zm.513 0a.137.137 0 0 1 .113.048l.13-.111a.309.309 0 0 0-.244-.108zm.123.058a.137.137 0 0 1 .048.113h.171a.309.309 0 0 0-.108-.243zm.048.113v.49h.171v-.49zm.155.541a2.033 2.033 0 0 1 1.759-.823v-.171a2.2 2.2 0 0 0-1.9.894zm1.759-.823a2.007 2.007 0 0 1 1.683.7l.135-.106a2.177 2.177 0 0 0-1.818-.768zm1.683.7a3.045 3.045 0 0 1 .617 1.845l.171-.007a3.218 3.218 0 0 0-.654-1.946zm.617 1.85c.007.078.011.2.011.372h.171c0-.171 0-.3-.012-.387zm.011.372c0 .171 0 .294-.011.372l.17.015c.008-.086.012-.216.012-.387zm-.011.376a3.08 3.08 0 0 1-.617 1.846l.134.106a3.25 3.25 0 0 0 .654-1.945zm-.617 1.845a2.025 2.025 0 0 1-1.683.7v.171a2.2 2.2 0 0 0 1.817-.768zm-1.683.7a2.068 2.068 0 0 1-1.739-.8l-.136.1a2.239 2.239 0 0 0 1.874.87zm-1.892-.75v2.587h.172v-2.587zm0 2.587a.156.156 0 0 1-.042.118l.121.121a.325.325 0 0 0 .092-.239zm-.046.123a.138.138 0 0 1-.114.048v.172a.308.308 0 0 0 .244-.108zm-.114.048h-.546v.172h.546zm1.817-2.739a1.408 1.408 0 0 0 1.218-.526l-.138-.1a1.24 1.24 0 0 1-1.079.455zm1.217-.525a2.355 2.355 0 0 0 .419-1.341l-.171-.007a2.182 2.182 0 0 1-.385 1.246zm.418-1.336c.008-.079.012-.19.012-.332h-.172c0 .14 0 .245-.011.315zm.012-.332a2.726 2.726 0 0 0-.407-1.632 1.448 1.448 0 0 0-1.24-.562v.171a1.278 1.278 0 0 1 1.1.492 2.565 2.565 0 0 1 .374 1.53zm-1.647-2.193a1.452 1.452 0 0 0-1.228.547l.136.1a1.282 1.282 0 0 1 1.091-.479zm-1.228.547a2.2 2.2 0 0 0-.43 1.252l.172.008a2.028 2.028 0 0 1 .4-1.157zm-.43 1.254l-.011.424h.171l.011-.424zm-.011.428l.011.435h.172l-.011-.435zm.011.436a1.95 1.95 0 0 0 .443 1.2l.133-.109a1.776 1.776 0 0 1-.4-1.1zm.443 1.2a1.484 1.484 0 0 0 1.214.522v-.171a1.314 1.314 0 0 1-1.082-.459zm5.828 1.117l.037-.077zm-.747-.6l-.07.049zm.335-2.063l.052.068zm1.65-.624l.012.085zm1.661-.234l.012.085a.086.086 0 0 0 .074-.085zm-2.107-1.249l.046.072zm-.468.48l-.075-.042a.083.083 0 0 0-.006.015zm-.089.145l-.054-.067-.007.006zm-.792-.022l-.065.056.009.009zm-.067-.178h-.086zm.245-.6l-.07-.049zm.747-.591l.038.077zm3.033.334l-.063.058zm.468 5.252l.06.061zm-.881 0l-.065.056a.043.043 0 0 0 .009.009zm-.067-.669h.086a.086.086 0 0 0-.156-.048zm-.714.6l-.04-.076zm.223-1.059l-.062-.06zm.468-1.684h.086a.086.086 0 0 0-.1-.085zm-1.293.189l.012.085zm-1.193.379l.046.072zm-.033 1.349l-.047.071zm.635.985a2.241 2.241 0 0 1-.978-.215l-.074.155a2.412 2.412 0 0 0 1.051.231zm-.978-.215a1.859 1.859 0 0 1-.715-.576l-.138.1a2.024 2.024 0 0 0 .779.629zm-.713-.573a1.4 1.4 0 0 1-.253-.81h-.172a1.571 1.571 0 0 0 .283.907zm-.253-.81a1.374 1.374 0 0 1 .569-1.136l-.105-.135a1.544 1.544 0 0 0-.635 1.272zm.569-1.137a3.316 3.316 0 0 1 1.609-.607l-.024-.17a3.481 3.481 0 0 0-1.691.642zm1.609-.607l1.661-.234-.024-.17-1.662.234zm1.735-.319v-.323h-.171v.323zm0-.323a1.156 1.156 0 0 0-.355-.917 1.536 1.536 0 0 0-1.035-.306v.172a1.37 1.37 0 0 1 .922.263.986.986 0 0 1 .3.788zm-1.39-1.223a1.486 1.486 0 0 0-.851.227l.1.142a1.316 1.316 0 0 1 .755-.2zm-.849.226a1.452 1.452 0 0 0-.5.51l.15.084a1.286 1.286 0 0 1 .44-.449zm-.5.524a.226.226 0 0 1-.062.105l.107.134a.391.391 0 0 0 .117-.185zm-.068.112a.1.1 0 0 1-.073.019v.171a.266.266 0 0 0 .194-.07zm-.073.019h-.48v.171h.48zm-.48 0a.18.18 0 0 1-.122-.046l-.112.13a.352.352 0 0 0 .234.087zm-.113-.037a.18.18 0 0 1-.047-.123h-.171a.352.352 0 0 0 .087.234zm-.047-.119a1.1 1.1 0 0 1 .23-.557l-.14-.1a1.253 1.253 0 0 0-.261.648zm.23-.556a1.843 1.843 0 0 1 .715-.564l-.075-.154a2.018 2.018 0 0 0-.78.618zm.716-.564a2.611 2.611 0 0 1 1.2-.247v-.171a2.781 2.781 0 0 0-1.277.266zm1.2-.247a2.268 2.268 0 0 1 1.732.563l.126-.116a2.435 2.435 0 0 0-1.858-.618zm1.733.564a1.945 1.945 0 0 1 .523 1.391h.171a2.117 2.117 0 0 0-.57-1.508zm.523 1.391v3.613h.171v-3.613zm0 3.613a.172.172 0 0 1-.053.129l.121.121a.344.344 0 0 0 .1-.25zm-.053.129a.157.157 0 0 1-.118.042v.171a.326.326 0 0 0 .239-.092zm-.118.042h-.513v.171h.513zm-.513 0a.2.2 0 0 1-.134-.046l-.111.13a.367.367 0 0 0 .245.088zm-.124-.037a.194.194 0 0 1-.047-.134h-.171a.366.366 0 0 0 .087.245zm-.047-.134v-.479h-.171v.479zm-.156-.528a1.846 1.846 0 0 1-.683.575l.079.152a2.012 2.012 0 0 0 .745-.629zm-.683.575a2.476 2.476 0 0 1-1.153.236v.171a2.644 2.644 0 0 0 1.233-.255zm-.919-.429a1.666 1.666 0 0 0 1.244-.494l-.123-.12a1.493 1.493 0 0 1-1.121.442zm1.244-.494a1.969 1.969 0 0 0 .492-1.431h-.171a1.8 1.8 0 0 1-.444 1.312zm.492-1.431v-.312h-.171v.312zm-.1-.4l-1.293.189.025.17 1.293-.189zm-1.293.189a3 3 0 0 0-1.228.393l.095.143a2.837 2.837 0 0 1 1.158-.365zm-1.227.392a.845.845 0 0 0-.441.73h.172a.676.676 0 0 1 .362-.586zm-.441.73a.869.869 0 0 0 .406.762l.095-.142a.7.7 0 0 1-.33-.62zm.408.764a1.673 1.673 0 0 0 .916.247v-.171a1.5 1.5 0 0 1-.823-.221zm5.686.329l-.061.06zm-.714-1.9h-.085zm-.011-.446h-.085zm.011-.446h-.085zm.714-1.885l.061.061zm3.234-.39l-.04.076zm.825.713l-.073.046zm.3.848h-.086zm-.067.178l.056.065zm-.892.022l.054-.067zm-.112-.178l-.081.029zm-.535-.758l-.048.071zm-1.974.2l-.062-.059zm-.435 1.3h-.086zm-.011.4h-.086zm.011.379h-.086zm.435 1.316l-.062.059zm1.974.2l.046.072zm.535-.769l-.079-.033zm.112-.178l.054.067.007-.006zm.892.022l-.061.06zm.067.178l-.085-.009zm-.3.847l-.072-.046zm-.825.714l-.04-.076zm-1.36.2a2.471 2.471 0 0 1-1.814-.644l-.12.122a2.64 2.64 0 0 0 1.933.694zm-1.813-.643a2.653 2.653 0 0 1-.689-1.839l-.171.006a2.822 2.822 0 0 0 .738 1.952zm-.689-1.838l-.011-.446h-.171l.011.446zm-.011-.442l.011-.446h-.171l-.011.446zm.011-.445a2.611 2.611 0 0 1 .689-1.827l-.122-.121a2.78 2.78 0 0 0-.738 1.942zm.689-1.827a2.447 2.447 0 0 1 1.813-.655v-.171a2.617 2.617 0 0 0-1.934.705zm1.813-.655a2.836 2.836 0 0 1 1.32.28l.079-.152a3 3 0 0 0-1.4-.3zm1.32.28a1.99 1.99 0 0 1 .792.683l.145-.091a2.158 2.158 0 0 0-.858-.744zm.793.685a1.617 1.617 0 0 1 .287.8l.171-.009a1.789 1.789 0 0 0-.315-.89zm.287.809a.11.11 0 0 1-.037.1l.112.13a.281.281 0 0 0 .1-.252zm-.037.1a.2.2 0 0 1-.134.046v.171a.369.369 0 0 0 .246-.088zm-.134.046h-.535v.171h.535zm-.535 0a.184.184 0 0 1-.114-.026l-.107.134a.345.345 0 0 0 .221.064zm-.114-.026a.389.389 0 0 1-.086-.144l-.158.066a.533.533 0 0 0 .137.212zm-.084-.14a1.514 1.514 0 0 0-.57-.8l-.093.144a1.343 1.343 0 0 1 .5.715zm-.568-.8a1.6 1.6 0 0 0-.918-.249v.171a1.435 1.435 0 0 1 .822.219zm-.918-.249a1.535 1.535 0 0 0-1.166.462l.124.118a1.364 1.364 0 0 1 1.042-.408zm-1.166.462a2.036 2.036 0 0 0-.458 1.36l.171.006a1.872 1.872 0 0 1 .411-1.249zm-.458 1.361l-.011.4h.171l.011-.4zm-.011.406l.011.379.171-.005-.011-.379zm.011.38a2.052 2.052 0 0 0 .458 1.371l.124-.118a1.889 1.889 0 0 1-.411-1.26zm.458 1.371a1.533 1.533 0 0 0 1.166.451v-.172a1.363 1.363 0 0 1-1.042-.4zm1.166.451a1.661 1.661 0 0 0 .916-.237l-.093-.144a1.491 1.491 0 0 1-.823.209zm.918-.238a1.576 1.576 0 0 0 .568-.812l-.162-.057a1.409 1.409 0 0 1-.5.727zm.566-.807a.39.39 0 0 1 .086-.144l-.107-.134a.533.533 0 0 0-.137.213zm.093-.151a.144.144 0 0 1 .107-.031v-.171a.31.31 0 0 0-.228.081zm.107-.031h.535v-.171h-.535zm.535 0a.173.173 0 0 1 .129.053l.121-.121a.344.344 0 0 0-.25-.1zm.134.057a.11.11 0 0 1 .037.1l.17.017a.281.281 0 0 0-.1-.252zm.037.109a1.664 1.664 0 0 1-.288.806l.144.092a1.839 1.839 0 0 0 .315-.889zm-.288.806a1.989 1.989 0 0 1-.792.683l.079.152a2.162 2.162 0 0 0 .858-.744zm-.793.684a2.8 2.8 0 0 1-1.32.28v.171a2.96 2.96 0 0 0 1.4-.3zm2.568.187l-.065.056.01.009zm0-7.772l.061.06zm.926 0l-.065.056.009.009zm.078 2.776h-.085a.086.086 0 0 0 .153.053zm.758-.624l.038.077zm2.743.468l-.065.056zm.524 5.151l-.061-.06zm-.925 0l-.065.056.009.009zm-.457-4.5l-.065.056zm-2.23.011l-.062-.059zm-.49 4.493l-.061-.06zm-.736-.019a.2.2 0 0 1-.134-.046l-.112.13a.367.367 0 0 0 .245.088zm-.124-.037a.2.2 0 0 1-.046-.134h-.172a.367.367 0 0 0 .087.245zm-.046-.134v-7.4h-.172v7.4zm0-7.4a.156.156 0 0 1 .042-.118l-.121-.121a.326.326 0 0 0-.092.239zm.042-.118a.172.172 0 0 1 .129-.053v-.171a.343.343 0 0 0-.25.1zm.129-.053h.557v-.171h-.557zm.557 0a.137.137 0 0 1 .113.048l.13-.112a.308.308 0 0 0-.244-.108zm.122.057a.137.137 0 0 1 .048.113h.172a.309.309 0 0 0-.108-.243zm.048.113v2.6h.172v-2.6zm.153 2.651a2.076 2.076 0 0 1 .728-.6l-.075-.154a2.248 2.248 0 0 0-.788.649zm.73-.6a2.272 2.272 0 0 1 1.043-.214v-.171a2.438 2.438 0 0 0-1.121.232zm1.043-.214a1.982 1.982 0 0 1 1.6.661l.13-.112a2.152 2.152 0 0 0-1.727-.721zm1.6.663a2.557 2.557 0 0 1 .581 1.761h.171a2.727 2.727 0 0 0-.624-1.874zm.581 1.761v3.144h.171v-3.144zm0 3.144a.173.173 0 0 1-.053.129l.121.121a.345.345 0 0 0 .1-.25zm-.053.129a.156.156 0 0 1-.118.042v.171a.327.327 0 0 0 .239-.092zm-.118.042h-.557v.171h.557zm-.557 0a.2.2 0 0 1-.134-.046l-.112.13a.367.367 0 0 0 .245.088zm-.124-.037a.2.2 0 0 1-.046-.134h-.172a.368.368 0 0 0 .087.245zm-.046-.134V823.8h-.172v3.088zm0-3.088a1.859 1.859 0 0 0-.412-1.284l-.128.114a1.69 1.69 0 0 1 .368 1.169zm-.411-1.283a1.471 1.471 0 0 0-1.169-.464v.171a1.3 1.3 0 0 1 1.039.406zm-1.169-.464a1.566 1.566 0 0 0-1.188.473l.124.118a1.4 1.4 0 0 1 1.064-.419zm-1.188.473a1.779 1.779 0 0 0-.436 1.275h.172a1.609 1.609 0 0 1 .389-1.156zm-.436 1.275v3.088h.172V823.8zm0 3.088a.172.172 0 0 1-.053.129l.121.121a.344.344 0 0 0 .1-.25zm-.053.129a.156.156 0 0 1-.118.042v.171a.327.327 0 0 0 .239-.092zm-.118.042h-.557v.171h.557zm6.449-.505l-.062.059zm-.747-1.94h-.086zm-.012-.379h-.085v.005zm.012-.368l-.086-.006zm.758-1.918l-.061-.06zm3.735.078l-.065.056zm.6 2.5l.061.061zm-4.036.067v-.086a.086.086 0 0 0-.086.086zm0 .1h-.086zm.435 1.238l-.068.053zm1.918.3l.045.073zm.491-.435l-.069-.051zm.145-.156l.039.077h.006zm.9.022l-.055.066zm-.245.747l-.064-.057zm-.858.6l.035.078zm.267-3.189v.086a.086.086 0 0 0 .086-.086zm-.424-1.282l-.066.055zm-2.23 0l-.065-.055zm-.4 1.282h-.086a.086.086 0 0 0 .086.086zm1.528 3.349a2.38 2.38 0 0 1-1.779-.677l-.122.12a2.55 2.55 0 0 0 1.9.728zm-1.778-.676a2.86 2.86 0 0 1-.724-1.886l-.171.009a3.027 3.027 0 0 0 .771 1.995zm-.723-1.884l-.011-.379h-.171l.011.379zm-.011-.374l.011-.368-.172-.005-.011.368zm.011-.365a2.871 2.871 0 0 1 .735-1.864l-.124-.118a3.042 3.042 0 0 0-.782 1.971zm.734-1.864a2.331 2.331 0 0 1 1.756-.687v-.171a2.5 2.5 0 0 0-1.879.74zm1.756-.687a2.307 2.307 0 0 1 1.853.762l.13-.112a2.477 2.477 0 0 0-1.983-.821zm1.854.762a3.03 3.03 0 0 1 .659 2.062h.172a3.2 3.2 0 0 0-.7-2.175zm.659 2.062v.19h.172v-.19zm0 .19a.172.172 0 0 1-.053.129l.121.121a.345.345 0 0 0 .1-.25zm-.053.129a.156.156 0 0 1-.118.042v.171a.327.327 0 0 0 .239-.092zm-.118.042h-3.858v.171h3.858zm-3.944.086v.1h.172v-.1zm0 .1a2.2 2.2 0 0 0 .453 1.287l.135-.106a2.027 2.027 0 0 1-.417-1.189zm.454 1.288a1.418 1.418 0 0 0 1.148.533v-.171a1.247 1.247 0 0 1-1.015-.47zm1.148.533a1.647 1.647 0 0 0 .882-.214l-.09-.146a1.481 1.481 0 0 1-.791.188zm.882-.214a1.777 1.777 0 0 0 .515-.458l-.14-.1a1.613 1.613 0 0 1-.466.412zm.513-.456a1.251 1.251 0 0 1 .081-.1.28.28 0 0 1 .026-.025l.008-.006-.077-.153a.326.326 0 0 0-.083.068 1.55 1.55 0 0 0-.092.113zm.12-.134a.328.328 0 0 1 .146-.021v-.171a.468.468 0 0 0-.234.046zm.146-.021h.547v-.171h-.547zm.547 0a.166.166 0 0 1 .112.036l.11-.132a.337.337 0 0 0-.222-.076zm.112.036a.107.107 0 0 1 .036.09h.171a.277.277 0 0 0-.1-.222zm.036.09a.9.9 0 0 1-.291.534l.128.115a1.055 1.055 0 0 0 .334-.649zm-.291.535a2.42 2.42 0 0 1-.83.581l.072.156a2.6 2.6 0 0 0 .888-.624zm-.829.58a2.964 2.964 0 0 1-1.224.238v.171a3.133 3.133 0 0 0 1.295-.253zm.389-3.111v-.033h-.171v.033zm0-.033a1.9 1.9 0 0 0-.445-1.306l-.129.114a1.731 1.731 0 0 1 .4 1.192zm-.444-1.3a1.466 1.466 0 0 0-1.181-.521v.172a1.3 1.3 0 0 1 1.049.46zm-1.181-.521a1.466 1.466 0 0 0-1.18.521l.131.11a1.3 1.3 0 0 1 1.049-.46zm-1.181.521a1.965 1.965 0 0 0-.422 1.3h.172a1.794 1.794 0 0 1 .382-1.194zm-.422 1.3v.033h.172v-.033zm.086.119h3.055v-.171h-3.055z" fill="#51504f" data-name="Path 10" transform="translate(-1460.636 -807.945)"></path> |
| <path id="Path_11" d="M1519.066 884.011a.581.581 0 0 1-.567-.567 1.151 1.151 0 0 1 .028-.312l7.026-18.328a.881.881 0 0 1 .906-.623h1.926a.882.882 0 0 1 .907.623l7 18.328.057.312a.583.583 0 0 1-.567.567h-1.445a.735.735 0 0 1-.482-.142.9.9 0 0 1-.226-.34l-1.558-4.023h-9.292l-1.558 4.023a.8.8 0 0 1-.255.34.688.688 0 0 1-.453.142zm12.181-6.94l-3.824-10.056-3.823 10.055zm8.184-10.538a.592.592 0 0 1-.652-.651v-1.53a.714.714 0 0 1 .17-.482.656.656 0 0 1 .482-.2h1.785a.677.677 0 0 1 .68.68v1.53a.655.655 0 0 1-.2.481.713.713 0 0 1-.481.17zm.227 17.479a.593.593 0 0 1-.652-.652v-13.428a.611.611 0 0 1 .17-.453.656.656 0 0 1 .482-.2h1.359a.679.679 0 0 1 .652.651v13.427a.655.655 0 0 1-.2.482.613.613 0 0 1-.453.17zm6.861 0a.592.592 0 0 1-.651-.652v-13.4a.715.715 0 0 1 .17-.481.656.656 0 0 1 .482-.2h1.3a.677.677 0 0 1 .68.68v1.246a4.255 4.255 0 0 1 3.966-1.926h1.1a.679.679 0 0 1 .651.651v1.161a.566.566 0 0 1-.2.453.612.612 0 0 1-.453.17h-1.7a3.2 3.2 0 0 0-2.408.907 3.253 3.253 0 0 0-.879 2.408v8.328a.656.656 0 0 1-.2.482.716.716 0 0 1-.482.17zm12.234 0a.593.593 0 0 1-.651-.652v-11.814h-2.408a.592.592 0 0 1-.651-.651v-.963a.611.611 0 0 1 .17-.453.654.654 0 0 1 .481-.2h2.408v-1.417q0-4.816 4.872-4.815h1.586a.679.679 0 0 1 .652.651v.963a.656.656 0 0 1-.2.481.613.613 0 0 1-.453.17h-1.529a2.1 2.1 0 0 0-1.785.68 3.248 3.248 0 0 0-.51 2.011v1.275h6.062V863.7a.613.613 0 0 1 .17-.453.656.656 0 0 1 .482-.2h1.3a.679.679 0 0 1 .652.651v19.659a.655.655 0 0 1-.2.482.613.613 0 0 1-.454.17h-1.3a.592.592 0 0 1-.652-.652v-11.811h-6.062v11.813a.657.657 0 0 1-.2.482.614.614 0 0 1-.454.17zm20.9.283a6.487 6.487 0 0 1-4.844-1.757 6.837 6.837 0 0 1-1.813-4.674l-.029-1.218.029-1.218a6.732 6.732 0 0 1 1.841-4.646 7.389 7.389 0 0 1 9.631 0 6.736 6.736 0 0 1 1.841 4.646q.028.311.028 1.218t-.028 1.218a6.772 6.772 0 0 1-1.841 4.674 6.391 6.391 0 0 1-4.82 1.756zm0-2.181a3.582 3.582 0 0 0 2.8-1.133 4.931 4.931 0 0 0 1.133-3.258q.028-.283.028-1.076t-.028-1.076a4.931 4.931 0 0 0-1.133-3.258 3.582 3.582 0 0 0-2.8-1.133 3.671 3.671 0 0 0-2.833 1.133 4.83 4.83 0 0 0-1.1 3.258l-.028 1.076.028 1.076a4.83 4.83 0 0 0 1.1 3.258 3.671 3.671 0 0 0 2.828 1.132zm13.755 1.9a.846.846 0 0 1-.566-.17 1.321 1.321 0 0 1-.34-.538l-4.023-13.144-.056-.283a.575.575 0 0 1 .17-.425.641.641 0 0 1 .425-.17h1.246a.612.612 0 0 1 .453.17.646.646 0 0 1 .255.312l3.145 10.679 3.371-10.566a.761.761 0 0 1 .255-.4.726.726 0 0 1 .538-.2h.963a.728.728 0 0 1 .539.2.76.76 0 0 1 .255.4l3.371 10.566 3.144-10.679a.655.655 0 0 1 .2-.312.714.714 0 0 1 .482-.17h1.275a.542.542 0 0 1 .4.17.576.576 0 0 1 .17.425l-.057.283-3.994 13.144a1.323 1.323 0 0 1-.34.538.9.9 0 0 1-.6.17h-1.1a.86.86 0 0 1-.935-.708l-3.286-10.141-3.286 10.141a.928.928 0 0 1-.963.708z" fill="#51504f" data-name="Path 11" transform="translate(-1454.66 -838.62)"></path> |
| </g> |
| </g> |
| </g> |
| </svg> |
| |
| </a> |
| </div> |
| |
| <div id="content-close-button"> |
| <svg xmlns="http://www.w3.org/2000/svg" width="19.799" height="19.799" viewBox="0 0 19.799 19.799"> |
| <g id="Group_1574" data-name="Group 1574" transform="translate(-41.892 290.899)"> |
| <g id="Group_1291" data-name="Group 1291" transform="rotate(-45 -308.114 -187.077)"> |
| <rect id="Rectangle_461" width="26" height="2" fill="#51504f" data-name="Rectangle 461" rx="1" transform="translate(-.209)"></rect> |
| </g> |
| <g id="Group_1292" data-name="Group 1292" transform="rotate(45 372.48 -93.011)"> |
| <rect id="Rectangle_462" width="26" height="2" fill="#51504f" data-name="Rectangle 462" rx="1" transform="translate(-.209 -.178)"></rect> |
| </g> |
| </g> |
| </svg> |
| |
| </div> |
| |
| </nav> |
| <div class="content-drawer-container" id="content-drawer"> |
| <div class="content-drawer"> |
| <div class="td-sidebar"> |
| |
| <div id="docs-version-selector" class="docs-version-selector sidebar__version-selector"> |
| <a class="dropdown-toggle" href="#" id="versionDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" |
| aria-expanded="false"> |
| <span class="bodytext__medium--greyish-brown">Version: </span><span class="version">2.2.0</span> |
| </a> |
| <div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink"> |
| |
| </div> |
| <script type="application/x-template" id="version-item-template"> |
| <a class="dropdown-item"></a> |
| </script> |
| </div> |
| |
| <div class="searchb-box"> |
| <form class="search-form" action="search.html" method="get"> |
| <input class="search-form__input" type="text" name="q" placeholder="Search docs" size="16"> |
| <input type="hidden" name="check_keywords" value="yes" /> |
| <input type="hidden" name="area" value="default" /> |
| |
| <button class="search-form__button" type="submit"> |
| |
| <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"> |
| <g id="Group_1579" data-name="Group 1579" transform="translate(-41.001 -41)"> |
| <path id="Path_169" d="M71.415 64.687a7.215 7.215 0 1 0-6.729 6.728 7.222 7.222 0 0 0 6.729-6.728z" fill="none" data-name="Path 169" transform="translate(-14.277 -14.276)"></path> |
| <path id="Path_170" d="M60.863 59.8l-6.093-6.09a7.78 7.78 0 1 0-1.06 1.06l6.09 6.093a.468.468 0 0 0 .662 0l.4-.4a.468.468 0 0 0 .001-.663zM42.512 49.183a6.274 6.274 0 1 1 5.851 5.85 6.28 6.28 0 0 1-5.851-5.85z" fill="#51504f" data-name="Path 170"></path> |
| </g> |
| </svg> |
| </button> |
| </form> |
| </div> |
| |
| |
| <style> |
| .searchb-box { |
| margin-bottom: 26px; |
| } |
| .searchb-box .search-form { |
| width: 100%; |
| margin-top: 20px; |
| } |
| </style> |
| |
| |
| <div class="toctree" role="navigation" aria-label="main navigation"> |
| <p class="caption"><span class="caption-text">Content</span></p> |
| <ul class="current"> |
| <li class="toctree-l1"><a class="reference internal" href="index.html">Home</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="project.html">Project</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="license.html">License</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="start/index.html">Quick Start</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="installation/index.html">Installation</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="upgrading-from-1-10/index.html">Upgrading from 1.10 to 2</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="tutorial.html">Tutorial</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="tutorial_taskflow_api.html">Tutorial on the TaskFlow API</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="howto/index.html">How-to Guides</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="ui.html">UI / Screenshots</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="concepts/index.html">Concepts</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="executor/index.html">Executor</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="dag-run.html">DAG Runs</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="plugins.html">Plugins</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="security/index.html">Security</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="logging-monitoring/index.html">Logging & Monitoring</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="timezone.html">Time Zones</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="usage-cli.html">Using the CLI</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="integration.html">Integration</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="kubernetes.html">Kubernetes</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="lineage.html">Lineage</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="dag-serialization.html">DAG Serialization</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="modules_management.html">Modules Management</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="release-process.html">Release Policies</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="changelog.html">Changelog</a></li> |
| <li class="toctree-l1 current"><a class="current reference internal" href="#">Best Practices</a><ul> |
| <li class="toctree-l2"><a class="reference internal" href="#writing-a-dag">Writing a DAG</a><ul> |
| <li class="toctree-l3"><a class="reference internal" href="#creating-a-custom-operator-hook">Creating a Custom Operator/Hook</a></li> |
| <li class="toctree-l3"><a class="reference internal" href="#creating-a-task">Creating a task</a></li> |
| <li class="toctree-l3"><a class="reference internal" href="#deleting-a-task">Deleting a task</a></li> |
| <li class="toctree-l3"><a class="reference internal" href="#communication">Communication</a></li> |
| <li class="toctree-l3"><a class="reference internal" href="#top-level-python-code">Top level Python Code</a></li> |
| <li class="toctree-l3"><a class="reference internal" href="#dynamic-dag-generation">Dynamic DAG Generation</a><ul> |
| <li class="toctree-l4"><a class="reference internal" href="#dynamic-dags-with-environment-variables">Dynamic DAGs with environment variables</a></li> |
| <li class="toctree-l4"><a class="reference internal" href="#generating-python-code-with-embedded-meta-data">Generating Python code with embedded meta-data</a></li> |
| <li class="toctree-l4"><a class="reference internal" href="#dynamic-dags-with-external-configuration-from-a-structured-data-file">Dynamic DAGs with external configuration from a structured data file</a></li> |
| </ul> |
| </li> |
| <li class="toctree-l3"><a class="reference internal" href="#best-practices-airflow-variables">Airflow Variables</a></li> |
| <li class="toctree-l3"><a class="reference internal" href="#triggering-dags-after-changes">Triggering DAGs after changes</a></li> |
| </ul> |
| </li> |
| <li class="toctree-l2"><a class="reference internal" href="#reducing-dag-complexity">Reducing DAG complexity</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="#testing-a-dag">Testing a DAG</a><ul> |
| <li class="toctree-l3"><a class="reference internal" href="#dag-loader-test">DAG Loader Test</a></li> |
| <li class="toctree-l3"><a class="reference internal" href="#unit-tests">Unit tests</a></li> |
| <li class="toctree-l3"><a class="reference internal" href="#self-checks">Self-Checks</a></li> |
| <li class="toctree-l3"><a class="reference internal" href="#staging-environment">Staging environment</a></li> |
| </ul> |
| </li> |
| <li class="toctree-l2"><a class="reference internal" href="#mocking-variables-and-connections">Mocking variables and connections</a></li> |
| </ul> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="production-deployment.html">Production Deployment</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="faq.html">FAQ</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="privacy_notice.html">Privacy Notice</a></li> |
| </ul> |
| <p class="caption"><span class="caption-text">References</span></p> |
| <ul> |
| <li class="toctree-l1"><a class="reference internal" href="operators-and-hooks-ref.html">Operators and hooks</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="cli-and-env-variables-ref.html">CLI</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="templates-ref.html">Templates</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="python-api-ref.html">Python API</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="stable-rest-api-ref.html">Stable REST API</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="deprecated-rest-api-ref.html">Deprecated REST API</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="configurations-ref.html">Configurations</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="extra-packages-ref.html">Extra packages</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="migrations-ref.html">Database Migrations</a></li> |
| </ul> |
| |
| </div> |
| |
| <style type="text/css"> |
| .toctree { |
| } |
| .toctree li { |
| list-style: none; |
| } |
| .toctree .caption { |
| font-family: Roboto; |
| font-size: 18px; |
| font-weight: bold; |
| font-stretch: normal; |
| font-style: normal; |
| line-height: 1.33; |
| letter-spacing: normal; |
| color: #51504f; |
| padding-bottom: 13px; |
| text-transform: uppercase; |
| margin-bottom: 0; |
| } |
| .toctree .current > a:not([href="#"]) { |
| color: #017cee; |
| } |
| .toctree > ul { |
| padding-left: 0; |
| } |
| .toctree ul { |
| padding-left: 15px; |
| display: none; |
| } |
| .toctree > ul, |
| .toctree li.current > ul { |
| display: block; |
| } |
| |
| .toctree a .toctree-expand { |
| display: inline-block; |
| position: relative; |
| height: 1em; |
| } |
| |
| .toctree a .toctree-expand:before { |
| position: absolute; |
| top: 6px; |
| left: -12px; |
| content: '►'; |
| font-size: 7px; |
| } |
| .toctree .current > a > .toctree-expand:before { |
| content: '▼'; |
| } |
| |
| .toctree .current { |
| color: #017cee; |
| } |
| .toctree li { |
| font-family: Roboto; |
| font-size: 16px; |
| font-weight: normal; |
| font-stretch: normal; |
| font-style: normal; |
| line-height: 1.63; |
| letter-spacing: normal; |
| color: #707070; |
| } |
| |
| </style> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| <div class="d-flex"> |
| |
| |
| <div class="td-sidebar desktop-only d-print-none"> |
| |
| <div id="docs-version-selector" class="docs-version-selector sidebar__version-selector"> |
| <a class="dropdown-toggle" href="#" id="versionDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" |
| aria-expanded="false"> |
| <span class="bodytext__medium--greyish-brown">Version: </span><span class="version">2.2.0</span> |
| </a> |
| <div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink"> |
| |
| </div> |
| <script type="application/x-template" id="version-item-template"> |
| <a class="dropdown-item"></a> |
| </script> |
| </div> |
| |
| <div class="searchb-box"> |
| <form class="search-form" action="search.html" method="get"> |
| <input class="search-form__input" type="text" name="q" placeholder="Search docs" size="16"> |
| <input type="hidden" name="check_keywords" value="yes" /> |
| <input type="hidden" name="area" value="default" /> |
| |
| <button class="search-form__button" type="submit"> |
| |
| <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"> |
| <g id="Group_1579" data-name="Group 1579" transform="translate(-41.001 -41)"> |
| <path id="Path_169" d="M71.415 64.687a7.215 7.215 0 1 0-6.729 6.728 7.222 7.222 0 0 0 6.729-6.728z" fill="none" data-name="Path 169" transform="translate(-14.277 -14.276)"></path> |
| <path id="Path_170" d="M60.863 59.8l-6.093-6.09a7.78 7.78 0 1 0-1.06 1.06l6.09 6.093a.468.468 0 0 0 .662 0l.4-.4a.468.468 0 0 0 .001-.663zM42.512 49.183a6.274 6.274 0 1 1 5.851 5.85 6.28 6.28 0 0 1-5.851-5.85z" fill="#51504f" data-name="Path 170"></path> |
| </g> |
| </svg> |
| </button> |
| </form> |
| </div> |
| |
| |
| <style> |
| .searchb-box { |
| margin-bottom: 26px; |
| } |
| .searchb-box .search-form { |
| width: 100%; |
| margin-top: 20px; |
| } |
| </style> |
| |
| |
| <div class="toctree" role="navigation" aria-label="main navigation"> |
| <p class="caption"><span class="caption-text">Content</span></p> |
| <ul class="current"> |
| <li class="toctree-l1"><a class="reference internal" href="index.html">Home</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="project.html">Project</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="license.html">License</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="start/index.html">Quick Start</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="installation/index.html">Installation</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="upgrading-from-1-10/index.html">Upgrading from 1.10 to 2</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="tutorial.html">Tutorial</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="tutorial_taskflow_api.html">Tutorial on the TaskFlow API</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="howto/index.html">How-to Guides</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="ui.html">UI / Screenshots</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="concepts/index.html">Concepts</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="executor/index.html">Executor</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="dag-run.html">DAG Runs</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="plugins.html">Plugins</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="security/index.html">Security</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="logging-monitoring/index.html">Logging & Monitoring</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="timezone.html">Time Zones</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="usage-cli.html">Using the CLI</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="integration.html">Integration</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="kubernetes.html">Kubernetes</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="lineage.html">Lineage</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="dag-serialization.html">DAG Serialization</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="modules_management.html">Modules Management</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="release-process.html">Release Policies</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="changelog.html">Changelog</a></li> |
| <li class="toctree-l1 current"><a class="current reference internal" href="#">Best Practices</a><ul> |
| <li class="toctree-l2"><a class="reference internal" href="#writing-a-dag">Writing a DAG</a><ul> |
| <li class="toctree-l3"><a class="reference internal" href="#creating-a-custom-operator-hook">Creating a Custom Operator/Hook</a></li> |
| <li class="toctree-l3"><a class="reference internal" href="#creating-a-task">Creating a task</a></li> |
| <li class="toctree-l3"><a class="reference internal" href="#deleting-a-task">Deleting a task</a></li> |
| <li class="toctree-l3"><a class="reference internal" href="#communication">Communication</a></li> |
| <li class="toctree-l3"><a class="reference internal" href="#top-level-python-code">Top level Python Code</a></li> |
| <li class="toctree-l3"><a class="reference internal" href="#dynamic-dag-generation">Dynamic DAG Generation</a><ul> |
| <li class="toctree-l4"><a class="reference internal" href="#dynamic-dags-with-environment-variables">Dynamic DAGs with environment variables</a></li> |
| <li class="toctree-l4"><a class="reference internal" href="#generating-python-code-with-embedded-meta-data">Generating Python code with embedded meta-data</a></li> |
| <li class="toctree-l4"><a class="reference internal" href="#dynamic-dags-with-external-configuration-from-a-structured-data-file">Dynamic DAGs with external configuration from a structured data file</a></li> |
| </ul> |
| </li> |
| <li class="toctree-l3"><a class="reference internal" href="#best-practices-airflow-variables">Airflow Variables</a></li> |
| <li class="toctree-l3"><a class="reference internal" href="#triggering-dags-after-changes">Triggering DAGs after changes</a></li> |
| </ul> |
| </li> |
| <li class="toctree-l2"><a class="reference internal" href="#reducing-dag-complexity">Reducing DAG complexity</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="#testing-a-dag">Testing a DAG</a><ul> |
| <li class="toctree-l3"><a class="reference internal" href="#dag-loader-test">DAG Loader Test</a></li> |
| <li class="toctree-l3"><a class="reference internal" href="#unit-tests">Unit tests</a></li> |
| <li class="toctree-l3"><a class="reference internal" href="#self-checks">Self-Checks</a></li> |
| <li class="toctree-l3"><a class="reference internal" href="#staging-environment">Staging environment</a></li> |
| </ul> |
| </li> |
| <li class="toctree-l2"><a class="reference internal" href="#mocking-variables-and-connections">Mocking variables and connections</a></li> |
| </ul> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="production-deployment.html">Production Deployment</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="faq.html">FAQ</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="privacy_notice.html">Privacy Notice</a></li> |
| </ul> |
| <p class="caption"><span class="caption-text">References</span></p> |
| <ul> |
| <li class="toctree-l1"><a class="reference internal" href="operators-and-hooks-ref.html">Operators and hooks</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="cli-and-env-variables-ref.html">CLI</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="templates-ref.html">Templates</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="python-api-ref.html">Python API</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="stable-rest-api-ref.html">Stable REST API</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="deprecated-rest-api-ref.html">Deprecated REST API</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="configurations-ref.html">Configurations</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="extra-packages-ref.html">Extra packages</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="migrations-ref.html">Database Migrations</a></li> |
| </ul> |
| |
| </div> |
| |
| <style type="text/css"> |
| .toctree { |
| } |
| .toctree li { |
| list-style: none; |
| } |
| .toctree .caption { |
| font-family: Roboto; |
| font-size: 18px; |
| font-weight: bold; |
| font-stretch: normal; |
| font-style: normal; |
| line-height: 1.33; |
| letter-spacing: normal; |
| color: #51504f; |
| padding-bottom: 13px; |
| text-transform: uppercase; |
| margin-bottom: 0; |
| } |
| .toctree .current > a:not([href="#"]) { |
| color: #017cee; |
| } |
| .toctree > ul { |
| padding-left: 0; |
| } |
| .toctree ul { |
| padding-left: 15px; |
| display: none; |
| } |
| .toctree > ul, |
| .toctree li.current > ul { |
| display: block; |
| } |
| |
| .toctree a .toctree-expand { |
| display: inline-block; |
| position: relative; |
| height: 1em; |
| } |
| |
| .toctree a .toctree-expand:before { |
| position: absolute; |
| top: 6px; |
| left: -12px; |
| content: '►'; |
| font-size: 7px; |
| } |
| .toctree .current > a > .toctree-expand:before { |
| content: '▼'; |
| } |
| |
| .toctree .current { |
| color: #017cee; |
| } |
| .toctree li { |
| font-family: Roboto; |
| font-size: 16px; |
| font-weight: normal; |
| font-stretch: normal; |
| font-style: normal; |
| line-height: 1.63; |
| letter-spacing: normal; |
| color: #707070; |
| } |
| |
| </style> |
| </div> |
| |
| |
| |
| |
| <main class="col-12 col-md-9 col-xl-8" role="main"> |
| |
| |
| |
| |
| |
| |
| |
| |
| <div role="navigation" aria-label="breadcrumbs navigation" class="d-none d-md-block d-print-none"> |
| |
| <ul class="breadcrumb"> |
| |
| <li class="breadcrumb-item"><a href="index.html" class="icon icon-home"> Home</a></li> |
| |
| <li class="breadcrumb-item"><a href="best-practices.html"> Best Practices</a></li> |
| |
| </ul> |
| </div> |
| |
| <div class="rst-content"> |
| <div class="document"> |
| <div class="documentwrapper"> |
| <div class="bodywrapper"> |
| <div class="body" role="main"> |
| |
| <blockquote> |
| <div></div></blockquote> |
| <div class="section" id="best-practices"> |
| <span id="best-practice"></span><h1>Best Practices<a class="headerlink" href="#best-practices" title="Permalink to this headline">¶</a></h1> |
| <p>Creating a new DAG is a two-step process:</p> |
| <ul class="simple"> |
| <li><p>writing Python code to create a DAG object,</p></li> |
| <li><p>testing if the code meets our expectations</p></li> |
| </ul> |
| <p>This tutorial will introduce you to the best practices for these two steps.</p> |
| <div class="section" id="writing-a-dag"> |
| <span id="best-practice-writing-a-dag"></span><h2>Writing a DAG<a class="headerlink" href="#writing-a-dag" title="Permalink to this headline">¶</a></h2> |
| <p>Creating a new DAG in Airflow is quite simple. However, there are many things that you need to take care of |
| to ensure the DAG run or failure does not produce unexpected results.</p> |
| <div class="section" id="creating-a-custom-operator-hook"> |
| <h3>Creating a Custom Operator/Hook<a class="headerlink" href="#creating-a-custom-operator-hook" title="Permalink to this headline">¶</a></h3> |
| <p>Please follow our guide on <a class="reference internal" href="howto/custom-operator.html#custom-operator"><span class="std std-ref">custom Operators</span></a>.</p> |
| </div> |
| <div class="section" id="creating-a-task"> |
| <h3>Creating a task<a class="headerlink" href="#creating-a-task" title="Permalink to this headline">¶</a></h3> |
| <p>You should treat tasks in Airflow equivalent to transactions in a database. This |
| implies that you should never produce incomplete results from your tasks. An |
| example is not to produce incomplete data in <code class="docutils literal notranslate"><span class="pre">HDFS</span></code> or <code class="docutils literal notranslate"><span class="pre">S3</span></code> at the end of a |
| task.</p> |
| <p>Airflow can retry a task if it fails. Thus, the tasks should produce the same |
| outcome on every re-run. Some of the ways you can avoid producing a different |
| result -</p> |
| <ul class="simple"> |
| <li><p>Do not use INSERT during a task re-run, an INSERT statement might lead to |
| duplicate rows in your database. Replace it with UPSERT.</p></li> |
| <li><p>Read and write in a specific partition. Never read the latest available data |
| in a task. Someone may update the input data between re-runs, which results in |
| different outputs. A better way is to read the input data from a specific |
| partition. You can use <code class="docutils literal notranslate"><span class="pre">data_interval_start</span></code> as a partition. You should |
| follow this partitioning method while writing data in S3/HDFS as well.</p></li> |
| <li><p>The Python datetime <code class="docutils literal notranslate"><span class="pre">now()</span></code> function gives the current datetime object. This |
| function should never be used inside a task, especially to do the critical |
| computation, as it leads to different outcomes on each run. It's fine to use |
| it, for example, to generate a temporary log.</p></li> |
| </ul> |
| <div class="admonition tip"> |
| <p class="admonition-title">Tip</p> |
| <p>You should define repetitive parameters such as <code class="docutils literal notranslate"><span class="pre">connection_id</span></code> or S3 paths in <code class="docutils literal notranslate"><span class="pre">default_args</span></code> rather than declaring them for each task. |
| The <code class="docutils literal notranslate"><span class="pre">default_args</span></code> help to avoid mistakes such as typographical errors. Also, most connection types have unique parameter names in |
| tasks, so you can declare a connection only once in <code class="docutils literal notranslate"><span class="pre">default_args</span></code> (for example <code class="docutils literal notranslate"><span class="pre">gcp_conn_id</span></code>) and it is automatically |
| used by all operators that use this connection type.</p> |
| </div> |
| </div> |
| <div class="section" id="deleting-a-task"> |
| <h3>Deleting a task<a class="headerlink" href="#deleting-a-task" title="Permalink to this headline">¶</a></h3> |
| <p>Be careful when deleting a task from a DAG. You would not be able to see the Task in Graph View, Tree View, etc making |
| it difficult to check the logs of that Task from the Webserver. If that is not desired, please create a new DAG.</p> |
| </div> |
| <div class="section" id="communication"> |
| <h3>Communication<a class="headerlink" href="#communication" title="Permalink to this headline">¶</a></h3> |
| <p>Airflow executes tasks of a DAG on different servers in case you are using <a class="reference internal" href="executor/kubernetes.html"><span class="doc">Kubernetes executor</span></a> or <a class="reference internal" href="executor/celery.html"><span class="doc">Celery executor</span></a>. |
| Therefore, you should not store any file or config in the local filesystem as the next task is likely to run on a different server without access to it — for example, a task that downloads the data file that the next task processes. |
| In the case of <a class="reference internal" href="_api/airflow/executors/local_executor/index.html#airflow.executors.local_executor.LocalExecutor" title="airflow.executors.local_executor.LocalExecutor"><code class="xref py py-class docutils literal notranslate"><span class="pre">Local</span> <span class="pre">executor</span></code></a>, |
| storing a file on disk can make retries harder e.g., your task requires a config file that is deleted by another task in DAG.</p> |
| <p>If possible, use <code class="docutils literal notranslate"><span class="pre">XCom</span></code> to communicate small messages between tasks and a good way of passing larger data between tasks is to use a remote storage such as S3/HDFS. |
| For example, if we have a task that stores processed data in S3 that task can push the S3 path for the output data in <code class="docutils literal notranslate"><span class="pre">Xcom</span></code>, |
| and the downstream tasks can pull the path from XCom and use it to read the data.</p> |
| <p>The tasks should also not store any authentication parameters such as passwords or token inside them. |
| Where at all possible, use <a class="reference internal" href="concepts/connections.html"><span class="doc">Connections</span></a> to store data securely in Airflow backend and retrieve them using a unique connection id.</p> |
| </div> |
| <div class="section" id="top-level-python-code"> |
| <span id="best-practices-top-level-code"></span><h3>Top level Python Code<a class="headerlink" href="#top-level-python-code" title="Permalink to this headline">¶</a></h3> |
| <p>You should avoid writing the top level code which is not necessary to create Operators |
| and build DAG relations between them. This is because of the design decision for the scheduler of Airflow |
| and the impact the top-level code parsing speed on both performance and scalability of Airflow.</p> |
| <p>Airflow scheduler executes the code outside the Operator's <code class="docutils literal notranslate"><span class="pre">execute</span></code> methods with the minimum interval of |
| <a class="reference internal" href="configurations-ref.html#config-scheduler-min-file-process-interval"><span class="std std-ref">min_file_process_interval</span></a> seconds. This is done in order |
| to allow dynamic scheduling of the DAGs - where scheduling and dependencies might change over time and |
| impact the next schedule of the DAG. Airflow scheduler tries to continuously make sure that what you have |
| in DAGs is correctly reflected in scheduled tasks.</p> |
| <p>Specifically you should not run any database access, heavy computations and networking operations.</p> |
| <p>One of the important factors impacting DAG loading time, that might be overlooked by Python developers is |
| that top-level imports might take surprisingly a lot of time and they can generate a lot of overhead |
| and this can be easily avoided by converting them to local imports inside Python callables for example.</p> |
| <p>Consider the example below - the first DAG will parse significantly slower (in the orders of seconds) |
| than equivalent DAG where the <code class="docutils literal notranslate"><span class="pre">numpy</span></code> module is imported as local import in the callable.</p> |
| <p>Bad example:</p> |
| <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span> |
| |
| <span class="kn">from</span> <span class="nn">airflow</span> <span class="kn">import</span> <span class="n">DAG</span> |
| <span class="kn">from</span> <span class="nn">airflow.operators.python</span> <span class="kn">import</span> <span class="n">PythonOperator</span> |
| |
| <span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span> <span class="c1"># <-- THIS IS A VERY BAD IDEA! DON'T DO THAT!</span> |
| |
| <span class="k">with</span> <span class="n">DAG</span><span class="p">(</span> |
| <span class="n">dag_id</span><span class="o">=</span><span class="s2">"example_python_operator"</span><span class="p">,</span> |
| <span class="n">schedule_interval</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> |
| <span class="n">start_date</span><span class="o">=</span><span class="n">datetime</span><span class="p">(</span><span class="mi">2021</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> |
| <span class="n">catchup</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> |
| <span class="n">tags</span><span class="o">=</span><span class="p">[</span><span class="s2">"example"</span><span class="p">],</span> |
| <span class="p">)</span> <span class="k">as</span> <span class="n">dag</span><span class="p">:</span> |
| |
| <span class="k">def</span> <span class="nf">print_array</span><span class="p">():</span> |
| <span class="sd">"""Print Numpy array."""</span> |
| <span class="n">a</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="mi">15</span><span class="p">)</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">5</span><span class="p">)</span> |
| <span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> |
| <span class="k">return</span> <span class="n">a</span> |
| |
| <span class="n">run_this</span> <span class="o">=</span> <span class="n">PythonOperator</span><span class="p">(</span> |
| <span class="n">task_id</span><span class="o">=</span><span class="s2">"print_the_context"</span><span class="p">,</span> |
| <span class="n">python_callable</span><span class="o">=</span><span class="n">print_array</span><span class="p">,</span> |
| <span class="p">)</span> |
| </pre></div> |
| </div> |
| <p>Good example:</p> |
| <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span> |
| |
| <span class="kn">from</span> <span class="nn">airflow</span> <span class="kn">import</span> <span class="n">DAG</span> |
| <span class="kn">from</span> <span class="nn">airflow.operators.python</span> <span class="kn">import</span> <span class="n">PythonOperator</span> |
| |
| <span class="k">with</span> <span class="n">DAG</span><span class="p">(</span> |
| <span class="n">dag_id</span><span class="o">=</span><span class="s2">"example_python_operator"</span><span class="p">,</span> |
| <span class="n">schedule_interval</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> |
| <span class="n">start_date</span><span class="o">=</span><span class="n">datetime</span><span class="p">(</span><span class="mi">2021</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> |
| <span class="n">catchup</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> |
| <span class="n">tags</span><span class="o">=</span><span class="p">[</span><span class="s2">"example"</span><span class="p">],</span> |
| <span class="p">)</span> <span class="k">as</span> <span class="n">dag</span><span class="p">:</span> |
| |
| <span class="k">def</span> <span class="nf">print_array</span><span class="p">():</span> |
| <span class="sd">"""Print Numpy array."""</span> |
| <span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span> <span class="c1"># <- THIS IS HOW NUMPY SHOULD BE IMPORTED IN THIS CASE</span> |
| |
| <span class="n">a</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="mi">15</span><span class="p">)</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">5</span><span class="p">)</span> |
| <span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> |
| <span class="k">return</span> <span class="n">a</span> |
| |
| <span class="n">run_this</span> <span class="o">=</span> <span class="n">PythonOperator</span><span class="p">(</span> |
| <span class="n">task_id</span><span class="o">=</span><span class="s2">"print_the_context"</span><span class="p">,</span> |
| <span class="n">python_callable</span><span class="o">=</span><span class="n">print_array</span><span class="p">,</span> |
| <span class="p">)</span> |
| </pre></div> |
| </div> |
| </div> |
| <div class="section" id="dynamic-dag-generation"> |
| <h3>Dynamic DAG Generation<a class="headerlink" href="#dynamic-dag-generation" title="Permalink to this headline">¶</a></h3> |
| <p>Avoiding excessive processing at the top level code described in the previous chapter is especially important |
| in case of dynamic DAG configuration, which can be configured essentially in one of those ways:</p> |
| <ul class="simple"> |
| <li><p>via <a class="reference external" href="https://wiki.archlinux.org/title/environment_variables">environment variables</a> (not to be mistaken |
| with the <a class="reference internal" href="concepts/variables.html"><span class="doc">Airflow Variables</span></a>)</p></li> |
| <li><p>via externally provided, generated Python code, containing meta-data in the DAG folder</p></li> |
| <li><p>via externally provided, generated configuration meta-data file in the DAG folder</p></li> |
| </ul> |
| <p>All cases are described in the following sections.</p> |
| <div class="section" id="dynamic-dags-with-environment-variables"> |
| <h4>Dynamic DAGs with environment variables<a class="headerlink" href="#dynamic-dags-with-environment-variables" title="Permalink to this headline">¶</a></h4> |
| <p>If you want to use variables to configure your code, you should always use |
| <a class="reference external" href="https://wiki.archlinux.org/title/environment_variables">environment variables</a> in your |
| top-level code rather than <a class="reference internal" href="concepts/variables.html"><span class="doc">Airflow Variables</span></a>. Using Airflow Variables |
| at top-level code creates a connection to metadata DB of Airflow to fetch the value, which can slow |
| down parsing and place extra load on the DB. See the <a class="reference external" href="_best_practices/airflow_variables">Airflow Variables</a> |
| on how to make best use of Airflow Variables in your DAGs using Jinja templates .</p> |
| <p>For example you could set <code class="docutils literal notranslate"><span class="pre">DEPLOYMENT</span></code> variable differently for your production and development |
| environments. The variable <code class="docutils literal notranslate"><span class="pre">DEPLOYMENT</span></code> could be set to <code class="docutils literal notranslate"><span class="pre">PROD</span></code> in your production environment and to |
| <code class="docutils literal notranslate"><span class="pre">DEV</span></code> in your development environment. Then you could build your dag differently in production and |
| development environment, depending on the value of the environment variable.</p> |
| <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">deployment</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"DEPLOYMENT"</span><span class="p">,</span> <span class="s2">"PROD"</span><span class="p">)</span> |
| <span class="k">if</span> <span class="n">deployment</span> <span class="o">==</span> <span class="s2">"PROD"</span><span class="p">:</span> |
| <span class="n">task</span> <span class="o">=</span> <span class="n">Operator</span><span class="p">(</span><span class="n">param</span><span class="o">=</span><span class="s2">"prod-param"</span><span class="p">)</span> |
| <span class="k">elif</span> <span class="n">deployment</span> <span class="o">==</span> <span class="s2">"DEV"</span><span class="p">:</span> |
| <span class="n">task</span> <span class="o">=</span> <span class="n">Operator</span><span class="p">(</span><span class="n">param</span><span class="o">=</span><span class="s2">"dev-param"</span><span class="p">)</span> |
| </pre></div> |
| </div> |
| </div> |
| <div class="section" id="generating-python-code-with-embedded-meta-data"> |
| <h4>Generating Python code with embedded meta-data<a class="headerlink" href="#generating-python-code-with-embedded-meta-data" title="Permalink to this headline">¶</a></h4> |
| <p>You can externally generate Python code containing the meta-data as importable constants. |
| Such constant can then be imported directly by your DAG and used to construct the object and build |
| the dependencies. This makes it easy to import such code from multiple DAGs without the need to find, |
| load and parse the meta-data stored in the constant - this is done automatically by Python interpreter |
| when it processes the "import" statement. This sounds strange at first, but it is surprisingly easy |
| to generate such code and make sure this is a valid Python code that you can import from your DAGs.</p> |
| <p>For example assume you dynamically generate (in your DAG folder), the <code class="docutils literal notranslate"><span class="pre">my_company_utils/common.py</span></code> file:</p> |
| <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># This file is generated automatically !</span> |
| <span class="n">ALL_TASKS</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"task1"</span><span class="p">,</span> <span class="s2">"task2"</span><span class="p">,</span> <span class="s2">"task3"</span><span class="p">]</span> |
| </pre></div> |
| </div> |
| <p>Then you can import and use the <code class="docutils literal notranslate"><span class="pre">ALL_TASKS</span></code> constant in all your DAGs like that:</p> |
| <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">my_company_utils.common</span> <span class="kn">import</span> <span class="n">ALL_TASKS</span> |
| |
| <span class="k">with</span> <span class="n">DAG</span><span class="p">(</span><span class="n">dag_id</span><span class="o">=</span><span class="s2">"my_dag"</span><span class="p">,</span> <span class="n">schedule_interval</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">start_date</span><span class="o">=</span><span class="n">days_ago</span><span class="p">(</span><span class="mi">2</span><span class="p">))</span> <span class="k">as</span> <span class="n">dag</span><span class="p">:</span> |
| <span class="k">for</span> <span class="n">task</span> <span class="ow">in</span> <span class="n">ALL_TASKS</span><span class="p">:</span> |
| <span class="c1"># create your operators and relations here</span> |
| <span class="k">pass</span> |
| </pre></div> |
| </div> |
| <p>Don't forget that in this case you need to add empty <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code> file in the <code class="docutils literal notranslate"><span class="pre">my_company_utils</span></code> folder |
| and you should add the <code class="docutils literal notranslate"><span class="pre">my_company_utils/.*</span></code> line to <code class="docutils literal notranslate"><span class="pre">.airflowignore</span></code> file, so that the whole folder is |
| ignored by the scheduler when it looks for DAGs.</p> |
| </div> |
| <div class="section" id="dynamic-dags-with-external-configuration-from-a-structured-data-file"> |
| <h4>Dynamic DAGs with external configuration from a structured data file<a class="headerlink" href="#dynamic-dags-with-external-configuration-from-a-structured-data-file" title="Permalink to this headline">¶</a></h4> |
| <p>If you need to use a more complex meta-data to prepare your DAG structure and you would prefer to keep the |
| data in a structured non-python format, you should export the data to the DAG folder in a file and push |
| it to the DAG folder, rather than try to pull the data by the DAG's top-level code - for the reasons |
| explained in the parent <a class="reference external" href="_top-level-python-code">Top level Python code</a>.</p> |
| <p>The meta-data should be exported and stored together with the DAGs in a convenient file format (JSON, YAML |
| formats are good candidates) in DAG folder. Ideally, the meta-data should be published in the same |
| package/folder as the module of the DAG file you load it from, because then you can find location of |
| the meta-data file in your DAG easily. The location of the file to read can be found using the |
| <code class="docutils literal notranslate"><span class="pre">__file__</span></code> attribute of the module containing the DAG:</p> |
| <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">my_dir</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">abspath</span><span class="p">(</span><span class="vm">__file__</span><span class="p">))</span> |
| <span class="n">configuration_file_path</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">my_dir</span><span class="p">,</span> <span class="s2">"config.yaml"</span><span class="p">)</span> |
| <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">configuration_file_path</span><span class="p">)</span> <span class="k">as</span> <span class="n">yaml_file</span><span class="p">:</span> |
| <span class="n">configuration</span> <span class="o">=</span> <span class="n">yaml</span><span class="o">.</span><span class="n">safe_load</span><span class="p">(</span><span class="n">yaml_file</span><span class="p">)</span> |
| <span class="c1"># Configuration dict is available here</span> |
| </pre></div> |
| </div> |
| </div> |
| </div> |
| <div class="section" id="best-practices-airflow-variables"> |
| <span id="id3"></span><h3>Airflow Variables<a class="headerlink" href="#best-practices-airflow-variables" title="Permalink to this headline">¶</a></h3> |
| <p>As mentioned in the previous chapter, <a class="reference external" href="_top-level-python-code">Top level Python code</a>. you should avoid |
| using Airflow Variables at top level Python code of DAGs. You can use the Airflow Variables freely inside the |
| <code class="docutils literal notranslate"><span class="pre">execute()</span></code> methods of the operators, but you can also pass the Airflow Variables to the existing operators |
| via Jinja template, which will delay reading the value until the task execution.</p> |
| <p>The template syntax to do this is:</p> |
| <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">{{</span> <span class="n">var</span><span class="o">.</span><span class="n">value</span><span class="o">.<</span><span class="n">variable_name</span><span class="o">></span> <span class="p">}}</span> |
| </pre></div> |
| </div> |
| <p>or if you need to deserialize a json object from the variable :</p> |
| <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">{{</span> <span class="n">var</span><span class="o">.</span><span class="n">json</span><span class="o">.<</span><span class="n">variable_name</span><span class="o">></span> <span class="p">}}</span> |
| </pre></div> |
| </div> |
| <p>For security purpose, you're recommended to use the <a class="reference internal" href="security/secrets/secrets-backend/index.html#secrets-backend-configuration"><span class="std std-ref">Secrets Backend</span></a> |
| for any variable that contains sensitive data.</p> |
| </div> |
| <div class="section" id="triggering-dags-after-changes"> |
| <h3>Triggering DAGs after changes<a class="headerlink" href="#triggering-dags-after-changes" title="Permalink to this headline">¶</a></h3> |
| <p>Avoid triggering DAGs immediately after changing them or any other accompanying files that you change in the |
| DAG folder.</p> |
| <p>You should give the system sufficient time to process the changed files. This takes several steps. |
| First the files have to be distributed to scheduler - usually via distributed filesystem or Git-Sync, then |
| scheduler has to parse the Python files and store them in the database. Depending on your configuration, |
| speed of your distributed filesystem, number of files, number of DAGs, number of changes in the files, |
| sizes of the files, number of schedulers, speed of CPUS, this can take from seconds to minutes, in extreme |
| cases many minutes. You should wait for your DAG to appear in the UI to be able to trigger it.</p> |
| <p>In case you see long delays between updating it and the time it is ready to be triggered, you can look |
| at the following configuration parameters and fine tune them according your needs (see details of |
| each parameter by following the links):</p> |
| <ul class="simple"> |
| <li><p><a class="reference internal" href="configurations-ref.html#config-scheduler-scheduler-idle-sleep-time"><span class="std std-ref">scheduler_idle_sleep_time</span></a></p></li> |
| <li><p><a class="reference internal" href="configurations-ref.html#config-scheduler-min-file-process-interval"><span class="std std-ref">min_file_process_interval</span></a></p></li> |
| <li><p><a class="reference internal" href="configurations-ref.html#config-scheduler-dag-dir-list-interval"><span class="std std-ref">dag_dir_list_interval</span></a></p></li> |
| <li><p><a class="reference internal" href="configurations-ref.html#config-scheduler-parsing-processes"><span class="std std-ref">parsing_processes</span></a></p></li> |
| <li><p><a class="reference internal" href="configurations-ref.html#config-scheduler-file-parsing-sort-mode"><span class="std std-ref">file_parsing_sort_mode</span></a></p></li> |
| </ul> |
| </div> |
| </div> |
| <div class="section" id="reducing-dag-complexity"> |
| <span id="best-practices-reducing-dag-complexity"></span><h2>Reducing DAG complexity<a class="headerlink" href="#reducing-dag-complexity" title="Permalink to this headline">¶</a></h2> |
| <p>While Airflow is good in handling a lot of DAGs with a lot of task and dependencies between them, when you |
| have many complex DAGs, their complexity might impact performance of scheduling. One of the ways to keep |
| your Airflow instance performant and well utilized, you should strive to simplify and optimize your DAGs |
| whenever possible - you have to remember that DAG parsing process and creation is just executing |
| Python code and it's up to you to make it as performant as possible. There are no magic recipes for making |
| your DAG "less complex" - since this is a Python code, it's the DAG writer who controls the complexity of |
| their code.</p> |
| <p>There are no "metrics" for DAG complexity, especially, there are no metrics that can tell you |
| whether your DAG is "simple enough". However - as with any Python code you can definitely tell that |
| your code is "simpler" or "faster" when you optimize it, the same can be said about DAG code. If you |
| want to optimize your DAGs there are the following actions you can take:</p> |
| <ul class="simple"> |
| <li><p>Make your DAG load faster. This is a single improvement advice that might be implemented in various ways |
| but this is the one that has biggest impact on scheduler's performance. Whenever you have a chance to make |
| your DAG load faster - go for it, if your goal is to improve performance. Look at the |
| <a class="reference internal" href="#best-practices-top-level-code"><span class="std std-ref">Top level Python Code</span></a> to get some tips of how you can do it. Also see at |
| <a class="reference internal" href="#best-practices-dag-loader-test"><span class="std std-ref">DAG Loader Test</span></a> on how to asses your DAG loading time.</p></li> |
| <li><p>Make your DAG generate simpler structure. Every task dependency adds additional processing overhead for |
| scheduling and execution. The DAG that has simple linear structure <code class="docutils literal notranslate"><span class="pre">A</span> <span class="pre">-></span> <span class="pre">B</span> <span class="pre">-></span> <span class="pre">C</span></code> will experience |
| less delays in task scheduling that DAG that has a deeply nested tree structure with exponentially growing |
| number of depending tasks for example. If you can make your DAGs more linear - where at single point in |
| execution there are as few potential candidates to run among the tasks, this will likely improve overall |
| scheduling performance.</p></li> |
| <li><p>Make smaller number of DAGs per file. While Airflow 2 is optimized for the case of having multiple DAGs |
| in one file, there are some parts of the system that make it sometimes less performant, or introduce more |
| delays than having those DAGs split among many files. Just the fact that one file can only be parsed by one |
| FileProcessor, makes it less scalable for example. If you have many DAGs generated from one file, |
| consider splitting them if you observe it takes a long time to reflect changes in your DAG files in the |
| UI of Airflow.</p></li> |
| </ul> |
| </div> |
| <div class="section" id="testing-a-dag"> |
| <h2>Testing a DAG<a class="headerlink" href="#testing-a-dag" title="Permalink to this headline">¶</a></h2> |
| <p>Airflow users should treat DAGs as production level code, and DAGs should have various associated tests to |
| ensure that they produce expected results. You can write a wide variety of tests for a DAG. |
| Let's take a look at some of them.</p> |
| <div class="section" id="dag-loader-test"> |
| <span id="best-practices-dag-loader-test"></span><h3>DAG Loader Test<a class="headerlink" href="#dag-loader-test" title="Permalink to this headline">¶</a></h3> |
| <p>This test should ensure that your DAG does not contain a piece of code that raises error while loading. |
| No additional code needs to be written by the user to run this test.</p> |
| <div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>python your-dag-file.py |
| </pre></div> |
| </div> |
| <p>Running the above command without any error ensures your DAG does not contain any uninstalled dependency, |
| syntax errors, etc. Make sure that you load your DAG in an environment that corresponds to your |
| scheduler environment - with the same dependencies, environment variables, common code referred from the |
| DAG.</p> |
| <p>This is also a great way to check if your DAG loads faster after an optimization, if you want to attempt |
| to optimize DAG loading time. Simply run the DAG and measure the time it takes, but again you have to |
| make sure your DAG runs with the same dependencies, environment variables, common code.</p> |
| <p>There are many ways to measure the time of processing, one of them in Linux environment is to |
| use built-in <code class="docutils literal notranslate"><span class="pre">time</span></code> command. Make sure to run it several times in succession to account for |
| caching effects. Compare the results before and after the optimization (in the same conditions - using |
| the same machine, environment etc.) in order to assess the impact of the optimization.</p> |
| <div class="highlight-bash notranslate"><div class="highlight"><pre><span></span><span class="nb">time</span> python airflow/example_dags/example_python_operator.py |
| </pre></div> |
| </div> |
| <p>Result:</p> |
| <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>real 0m0.699s |
| user 0m0.590s |
| sys 0m0.108s |
| </pre></div> |
| </div> |
| <p>The important metrics is the "real time" - which tells you how long time it took |
| to process the DAG. Note that when loading the file this way, you are starting a new interpreter so there is |
| an initial loading time that is not present when Airflow parses the DAG. You can assess the |
| time of initialization by running:</p> |
| <div class="highlight-bash notranslate"><div class="highlight"><pre><span></span><span class="nb">time</span> python -c <span class="s1">''</span> |
| </pre></div> |
| </div> |
| <p>Result:</p> |
| <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>real 0m0.073s |
| user 0m0.037s |
| sys 0m0.039s |
| </pre></div> |
| </div> |
| <p>In this case the initial interpreter startup time is ~ 0.07s which is about 10% of time needed to parse |
| the example_python_operator.py above so the actual parsing time is about ~ 0.62 s for the example DAG.</p> |
| <p>You can look into <a class="reference internal" href="tutorial.html#testing"><span class="std std-ref">Testing a DAG</span></a> for details on how to test individual operators.</p> |
| </div> |
| <div class="section" id="unit-tests"> |
| <h3>Unit tests<a class="headerlink" href="#unit-tests" title="Permalink to this headline">¶</a></h3> |
| <p>Unit tests ensure that there is no incorrect code in your DAG. You can write unit tests for both your tasks and your DAG.</p> |
| <p><strong>Unit test for loading a DAG:</strong></p> |
| <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">pytest</span> |
| |
| <span class="kn">from</span> <span class="nn">airflow.models</span> <span class="kn">import</span> <span class="n">DagBag</span> |
| |
| |
| <span class="nd">@pytest</span><span class="o">.</span><span class="n">fixture</span><span class="p">()</span> |
| <span class="k">def</span> <span class="nf">dagbag</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> |
| <span class="k">return</span> <span class="n">DagBag</span><span class="p">()</span> |
| |
| |
| <span class="k">def</span> <span class="nf">test_dag_loaded</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dagbag</span><span class="p">):</span> |
| <span class="n">dag</span> <span class="o">=</span> <span class="n">dagbag</span><span class="o">.</span><span class="n">get_dag</span><span class="p">(</span><span class="n">dag_id</span><span class="o">=</span><span class="s2">"hello_world"</span><span class="p">)</span> |
| <span class="k">assert</span> <span class="n">dagbag</span><span class="o">.</span><span class="n">import_errors</span> <span class="o">==</span> <span class="p">{}</span> |
| <span class="k">assert</span> <span class="n">dag</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> |
| <span class="k">assert</span> <span class="nb">len</span><span class="p">(</span><span class="n">dag</span><span class="o">.</span><span class="n">tasks</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span> |
| </pre></div> |
| </div> |
| <p><strong>Unit test a DAG structure:</strong> |
| This is an example test want to verify the structure of a code-generated DAG against a dict object</p> |
| <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">assert_dag_dict_equal</span><span class="p">(</span><span class="n">source</span><span class="p">,</span> <span class="n">dag</span><span class="p">):</span> |
| <span class="k">assert</span> <span class="n">dag</span><span class="o">.</span><span class="n">task_dict</span><span class="o">.</span><span class="n">keys</span><span class="p">()</span> <span class="o">==</span> <span class="n">source</span><span class="o">.</span><span class="n">keys</span><span class="p">()</span> |
| <span class="k">for</span> <span class="n">task_id</span><span class="p">,</span> <span class="n">downstream_list</span> <span class="ow">in</span> <span class="n">source</span><span class="o">.</span><span class="n">items</span><span class="p">():</span> |
| <span class="k">assert</span> <span class="n">dag</span><span class="o">.</span><span class="n">has_task</span><span class="p">(</span><span class="n">task_id</span><span class="p">)</span> |
| <span class="n">task</span> <span class="o">=</span> <span class="n">dag</span><span class="o">.</span><span class="n">get_task</span><span class="p">(</span><span class="n">task_id</span><span class="p">)</span> |
| <span class="k">assert</span> <span class="n">task</span><span class="o">.</span><span class="n">downstream_task_ids</span> <span class="o">==</span> <span class="nb">set</span><span class="p">(</span><span class="n">downstream_list</span><span class="p">)</span> |
| |
| |
| <span class="k">def</span> <span class="nf">test_dag</span><span class="p">():</span> |
| <span class="n">assert_dag_dict_equal</span><span class="p">(</span> |
| <span class="p">{</span> |
| <span class="s2">"DummyInstruction_0"</span><span class="p">:</span> <span class="p">[</span><span class="s2">"DummyInstruction_1"</span><span class="p">],</span> |
| <span class="s2">"DummyInstruction_1"</span><span class="p">:</span> <span class="p">[</span><span class="s2">"DummyInstruction_2"</span><span class="p">],</span> |
| <span class="s2">"DummyInstruction_2"</span><span class="p">:</span> <span class="p">[</span><span class="s2">"DummyInstruction_3"</span><span class="p">],</span> |
| <span class="s2">"DummyInstruction_3"</span><span class="p">:</span> <span class="p">[],</span> |
| <span class="p">},</span> |
| <span class="n">dag</span><span class="p">,</span> |
| <span class="p">)</span> |
| </pre></div> |
| </div> |
| <p><strong>Unit test for custom operator:</strong></p> |
| <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">datetime</span> |
| |
| <span class="kn">import</span> <span class="nn">pytest</span> |
| |
| <span class="kn">from</span> <span class="nn">airflow.utils.state</span> <span class="kn">import</span> <span class="n">DagRunState</span> |
| <span class="kn">from</span> <span class="nn">airflow.utils.types</span> <span class="kn">import</span> <span class="n">DagRunType</span> |
| |
| <span class="n">DATA_INTERVAL_START</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="p">(</span><span class="mi">2021</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">13</span><span class="p">)</span> |
| <span class="n">DATA_INTERVAL_END</span> <span class="o">=</span> <span class="n">DATA_INTERVAL_START</span> <span class="o">+</span> <span class="n">datetime</span><span class="o">.</span><span class="n">timedelta</span><span class="p">(</span><span class="n">days</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span> |
| |
| <span class="n">TEST_DAG_ID</span> <span class="o">=</span> <span class="s2">"my_custom_operator_dag"</span> |
| <span class="n">TEST_TASK_ID</span> <span class="o">=</span> <span class="s2">"my_custom_operator_task"</span> |
| |
| |
| <span class="nd">@pytest</span><span class="o">.</span><span class="n">fixture</span><span class="p">()</span> |
| <span class="k">def</span> <span class="nf">dag</span><span class="p">():</span> |
| <span class="k">with</span> <span class="n">DAG</span><span class="p">(</span> |
| <span class="n">dag_id</span><span class="o">=</span><span class="n">TEST_DAG_ID</span><span class="p">,</span> |
| <span class="n">schedule_interval</span><span class="o">=</span><span class="s2">"@daily"</span><span class="p">,</span> |
| <span class="n">default_args</span><span class="o">=</span><span class="p">{</span><span class="s2">"start_date"</span><span class="p">:</span> <span class="n">DATA_INTERVAL_START</span><span class="p">},</span> |
| <span class="p">)</span> <span class="k">as</span> <span class="n">dag</span><span class="p">:</span> |
| <span class="n">MyCustomOperator</span><span class="p">(</span> |
| <span class="n">task_id</span><span class="o">=</span><span class="n">TEST_TASK_ID</span><span class="p">,</span> |
| <span class="n">prefix</span><span class="o">=</span><span class="s2">"s3://bucket/some/prefix"</span><span class="p">,</span> |
| <span class="p">)</span> |
| <span class="k">return</span> <span class="n">dag</span> |
| |
| |
| <span class="k">def</span> <span class="nf">test_my_custom_operator_execute_no_trigger</span><span class="p">(</span><span class="n">dag</span><span class="p">):</span> |
| <span class="n">dagrun</span> <span class="o">=</span> <span class="n">dag</span><span class="o">.</span><span class="n">create_dagrun</span><span class="p">(</span> |
| <span class="n">state</span><span class="o">=</span><span class="n">DagRunState</span><span class="o">.</span><span class="n">RUNNING</span><span class="p">,</span> |
| <span class="n">execution_date</span><span class="o">=</span><span class="n">DATA_INTERVAL_START</span><span class="p">,</span> |
| <span class="n">data_interval</span><span class="o">=</span><span class="p">(</span><span class="n">DATA_INTERVAL_START</span><span class="p">,</span> <span class="n">DATA_INTERVAL_END</span><span class="p">),</span> |
| <span class="n">start_date</span><span class="o">=</span><span class="n">DATA_INTERVAL_END</span><span class="p">,</span> |
| <span class="n">run_type</span><span class="o">=</span><span class="n">DagRunType</span><span class="o">.</span><span class="n">MANUAL</span><span class="p">,</span> |
| <span class="p">)</span> |
| <span class="n">ti</span> <span class="o">=</span> <span class="n">dagrun</span><span class="o">.</span><span class="n">get_task_instance</span><span class="p">(</span><span class="n">task_id</span><span class="o">=</span><span class="n">TEST_TASK_ID</span><span class="p">)</span> |
| <span class="n">ti</span><span class="o">.</span><span class="n">task</span> <span class="o">=</span> <span class="n">dag</span><span class="o">.</span><span class="n">get_task</span><span class="p">(</span><span class="n">task_id</span><span class="o">=</span><span class="n">TEST_TASK_ID</span><span class="p">)</span> |
| <span class="n">ti</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">ignore_ti_state</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> |
| <span class="k">assert</span> <span class="n">ti</span><span class="o">.</span><span class="n">state</span> <span class="o">==</span> <span class="n">State</span><span class="o">.</span><span class="n">SUCCESS</span> |
| <span class="c1"># Assert something related to tasks results.</span> |
| </pre></div> |
| </div> |
| </div> |
| <div class="section" id="self-checks"> |
| <h3>Self-Checks<a class="headerlink" href="#self-checks" title="Permalink to this headline">¶</a></h3> |
| <p>You can also implement checks in a DAG to make sure the tasks are producing the results as expected. |
| As an example, if you have a task that pushes data to S3, you can implement a check in the next task. For example, the check could |
| make sure that the partition is created in S3 and perform some simple checks to determine if the data is correct.</p> |
| <p>Similarly, if you have a task that starts a microservice in Kubernetes or Mesos, you should check if the service has started or not using <a class="reference external" href="/docs/apache-airflow-providers-http/stable/_api/airflow/providers/http/sensors/http/index.html#airflow.providers.http.sensors.http.HttpSensor" title="(in apache-airflow-providers-http v2.0.1)"><code class="xref py py-class docutils literal notranslate"><span class="pre">airflow.providers.http.sensors.http.HttpSensor</span></code></a>.</p> |
| <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">task</span> <span class="o">=</span> <span class="n">PushToS3</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> |
| <span class="n">check</span> <span class="o">=</span> <span class="n">S3KeySensor</span><span class="p">(</span> |
| <span class="n">task_id</span><span class="o">=</span><span class="s2">"check_parquet_exists"</span><span class="p">,</span> |
| <span class="n">bucket_key</span><span class="o">=</span><span class="s2">"s3://bucket/key/foo.parquet"</span><span class="p">,</span> |
| <span class="n">poke_interval</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> |
| <span class="n">timeout</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> |
| <span class="p">)</span> |
| <span class="n">task</span> <span class="o">>></span> <span class="n">check</span> |
| </pre></div> |
| </div> |
| </div> |
| <div class="section" id="staging-environment"> |
| <h3>Staging environment<a class="headerlink" href="#staging-environment" title="Permalink to this headline">¶</a></h3> |
| <p>If possible, keep a staging environment to test the complete DAG run before deploying in the production. |
| Make sure your DAG is parameterized to change the variables, e.g., the output path of S3 operation or the database used to read the configuration. |
| Do not hard code values inside the DAG and then change them manually according to the environment.</p> |
| <p>You can use environment variables to parameterize the DAG.</p> |
| <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">os</span> |
| |
| <span class="n">dest</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"MY_DAG_DEST_PATH"</span><span class="p">,</span> <span class="s2">"s3://default-target/path/"</span><span class="p">)</span> |
| </pre></div> |
| </div> |
| </div> |
| </div> |
| <div class="section" id="mocking-variables-and-connections"> |
| <h2>Mocking variables and connections<a class="headerlink" href="#mocking-variables-and-connections" title="Permalink to this headline">¶</a></h2> |
| <p>When you write tests for code that uses variables or a connection, you must ensure that they exist when you run the tests. The obvious solution is to save these objects to the database so they can be read while your code is executing. However, reading and writing objects to the database are burdened with additional time overhead. In order to speed up the test execution, it is worth simulating the existence of these objects without saving them to the database. For this, you can create environment variables with mocking <a class="reference external" href="https://docs.python.org/3/library/os.html#os.environ" title="(in Python v3.10)"><code class="xref any docutils literal notranslate"><span class="pre">os.environ</span></code></a> using <code class="xref py py-meth docutils literal notranslate"><span class="pre">unittest.mock.patch.dict()</span></code>.</p> |
| <p>For variable, use <span class="target" id="index-0"></span><a class="reference internal" href="cli-and-env-variables-ref.html#envvar-AIRFLOW_VAR_-KEY"><code class="xref std std-envvar docutils literal notranslate"><span class="pre">AIRFLOW_VAR_{KEY}</span></code></a>.</p> |
| <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">with</span> <span class="n">mock</span><span class="o">.</span><span class="n">patch</span><span class="o">.</span><span class="n">dict</span><span class="p">(</span><span class="s2">"os.environ"</span><span class="p">,</span> <span class="n">AIRFLOW_VAR_KEY</span><span class="o">=</span><span class="s2">"env-value"</span><span class="p">):</span> |
| <span class="k">assert</span> <span class="s2">"env-value"</span> <span class="o">==</span> <span class="n">Variable</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"key"</span><span class="p">)</span> |
| </pre></div> |
| </div> |
| <p>For connection, use <span class="target" id="index-1"></span><a class="reference internal" href="cli-and-env-variables-ref.html#envvar-AIRFLOW_CONN_-CONN_ID"><code class="xref std std-envvar docutils literal notranslate"><span class="pre">AIRFLOW_CONN_{CONN_ID}</span></code></a>.</p> |
| <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">conn</span> <span class="o">=</span> <span class="n">Connection</span><span class="p">(</span> |
| <span class="n">conn_type</span><span class="o">=</span><span class="s2">"gcpssh"</span><span class="p">,</span> |
| <span class="n">login</span><span class="o">=</span><span class="s2">"cat"</span><span class="p">,</span> |
| <span class="n">host</span><span class="o">=</span><span class="s2">"conn-host"</span><span class="p">,</span> |
| <span class="p">)</span> |
| <span class="n">conn_uri</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">get_uri</span><span class="p">()</span> |
| <span class="k">with</span> <span class="n">mock</span><span class="o">.</span><span class="n">patch</span><span class="o">.</span><span class="n">dict</span><span class="p">(</span><span class="s2">"os.environ"</span><span class="p">,</span> <span class="n">AIRFLOW_CONN_MY_CONN</span><span class="o">=</span><span class="n">conn_uri</span><span class="p">):</span> |
| <span class="k">assert</span> <span class="s2">"cat"</span> <span class="o">==</span> <span class="n">Connection</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"my_conn"</span><span class="p">)</span><span class="o">.</span><span class="n">login</span> |
| </pre></div> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div class="pager" role="navigation" aria-label="related navigation"> |
| <a rel="prev" title="Changelog" href="changelog.html" > |
| <button class="btn-hollow btn-blue bodytext__medium--cerulean-blue" accesskey="p">Previous</button> |
| </a> |
| <a rel="next" title="Production Deployment" href="production-deployment.html" > |
| <button class="btn-hollow btn-blue bodytext__medium--cerulean-blue" accesskey="n">Next</button> |
| </a> |
| </div> |
| </div> |
| |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="rating-container"> |
| <p class="bodytext__medium--greyish-brown font-weight-500">Was this entry helpful?</p> |
| <div class="rating"> |
| |
| <div id="rate-star-5" class="rate-star"> |
| <svg xmlns="http://www.w3.org/2000/svg" width="21.05" height="20.02" viewBox="0 0 21.05 20.02"> |
| <g id="Group_806" data-name="Group 806" transform="translate(-774.404 -13.178)"> |
| <path id="Path_715" d="M791.434 33.2l-6.5-3.42-6.5 3.42 1.242-7.243-5.262-5.13 7.273-1.057 3.252-6.59 3.252 6.59 7.273 1.057-5.262 5.13z" fill="#017cee" data-name="Path 715"></path> |
| </g> |
| </svg> |
| |
| </div> |
| |
| <div id="rate-star-4" class="rate-star"> |
| <svg xmlns="http://www.w3.org/2000/svg" width="21.05" height="20.02" viewBox="0 0 21.05 20.02"> |
| <g id="Group_806" data-name="Group 806" transform="translate(-774.404 -13.178)"> |
| <path id="Path_715" d="M791.434 33.2l-6.5-3.42-6.5 3.42 1.242-7.243-5.262-5.13 7.273-1.057 3.252-6.59 3.252 6.59 7.273 1.057-5.262 5.13z" fill="#017cee" data-name="Path 715"></path> |
| </g> |
| </svg> |
| |
| </div> |
| |
| <div id="rate-star-3" class="rate-star"> |
| <svg xmlns="http://www.w3.org/2000/svg" width="21.05" height="20.02" viewBox="0 0 21.05 20.02"> |
| <g id="Group_806" data-name="Group 806" transform="translate(-774.404 -13.178)"> |
| <path id="Path_715" d="M791.434 33.2l-6.5-3.42-6.5 3.42 1.242-7.243-5.262-5.13 7.273-1.057 3.252-6.59 3.252 6.59 7.273 1.057-5.262 5.13z" fill="#017cee" data-name="Path 715"></path> |
| </g> |
| </svg> |
| |
| </div> |
| |
| <div id="rate-star-2" class="rate-star"> |
| <svg xmlns="http://www.w3.org/2000/svg" width="21.05" height="20.02" viewBox="0 0 21.05 20.02"> |
| <g id="Group_806" data-name="Group 806" transform="translate(-774.404 -13.178)"> |
| <path id="Path_715" d="M791.434 33.2l-6.5-3.42-6.5 3.42 1.242-7.243-5.262-5.13 7.273-1.057 3.252-6.59 3.252 6.59 7.273 1.057-5.262 5.13z" fill="#017cee" data-name="Path 715"></path> |
| </g> |
| </svg> |
| |
| </div> |
| |
| <div id="rate-star-1" class="rate-star"> |
| <svg xmlns="http://www.w3.org/2000/svg" width="21.05" height="20.02" viewBox="0 0 21.05 20.02"> |
| <g id="Group_806" data-name="Group 806" transform="translate(-774.404 -13.178)"> |
| <path id="Path_715" d="M791.434 33.2l-6.5-3.42-6.5 3.42 1.242-7.243-5.262-5.13 7.273-1.057 3.252-6.59 3.252 6.59 7.273 1.057-5.262 5.13z" fill="#017cee" data-name="Path 715"></path> |
| </g> |
| </svg> |
| |
| </div> |
| |
| </div> |
| </div> |
| |
| </main> |
| |
| |
| |
| |
| <nav class="wy-nav-side-toc"> |
| <div class="wy-menu-vertical"> |
| <ul> |
| <li><a class="reference internal" href="#">Best Practices</a><ul> |
| <li><a class="reference internal" href="#writing-a-dag">Writing a DAG</a><ul> |
| <li><a class="reference internal" href="#creating-a-custom-operator-hook">Creating a Custom Operator/Hook</a></li> |
| <li><a class="reference internal" href="#creating-a-task">Creating a task</a></li> |
| <li><a class="reference internal" href="#deleting-a-task">Deleting a task</a></li> |
| <li><a class="reference internal" href="#communication">Communication</a></li> |
| <li><a class="reference internal" href="#top-level-python-code">Top level Python Code</a></li> |
| <li><a class="reference internal" href="#dynamic-dag-generation">Dynamic DAG Generation</a><ul> |
| <li><a class="reference internal" href="#dynamic-dags-with-environment-variables">Dynamic DAGs with environment variables</a></li> |
| <li><a class="reference internal" href="#generating-python-code-with-embedded-meta-data">Generating Python code with embedded meta-data</a></li> |
| <li><a class="reference internal" href="#dynamic-dags-with-external-configuration-from-a-structured-data-file">Dynamic DAGs with external configuration from a structured data file</a></li> |
| </ul> |
| </li> |
| <li><a class="reference internal" href="#best-practices-airflow-variables">Airflow Variables</a></li> |
| <li><a class="reference internal" href="#triggering-dags-after-changes">Triggering DAGs after changes</a></li> |
| </ul> |
| </li> |
| <li><a class="reference internal" href="#reducing-dag-complexity">Reducing DAG complexity</a></li> |
| <li><a class="reference internal" href="#testing-a-dag">Testing a DAG</a><ul> |
| <li><a class="reference internal" href="#dag-loader-test">DAG Loader Test</a></li> |
| <li><a class="reference internal" href="#unit-tests">Unit tests</a></li> |
| <li><a class="reference internal" href="#self-checks">Self-Checks</a></li> |
| <li><a class="reference internal" href="#staging-environment">Staging environment</a></li> |
| </ul> |
| </li> |
| <li><a class="reference internal" href="#mocking-variables-and-connections">Mocking variables and connections</a></li> |
| </ul> |
| </li> |
| </ul> |
| |
| </div> |
| </nav> |
| |
| </div> |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| <div class="base-layout--button"> |
| <a href="https://github.com/apache/airflow/edit/main/docs/apache-airflow/best-practices.rst" rel="nofollow"> |
| |
| <button class="btn-hollow btn-brown btn-with-icon with-box-shadow button-fixed"> |
| <svg xmlns="http://www.w3.org/2000/svg" width="30.76" height="30"> |
| <path d="M15.379 0a15.381 15.381 0 00-4.86 29.974c.769.141 1.05-.334 1.05-.741 0-.365-.013-1.332-.021-2.616-4.278.929-5.181-2.062-5.181-2.062a4.071 4.071 0 00-1.708-2.25c-1.4-.954.106-.935.106-.935a3.231 3.231 0 012.356 1.585 3.274 3.274 0 004.476 1.278 3.287 3.287 0 01.976-2.056c-3.415-.388-7.005-1.707-7.005-7.6a5.947 5.947 0 011.583-4.127 5.53 5.53 0 01.151-4.07s1.291-.413 4.229 1.577a14.577 14.577 0 017.7 0c2.936-1.99 4.225-1.577 4.225-1.577a5.523 5.523 0 01.153 4.07 5.937 5.937 0 011.581 4.127c0 5.909-3.6 7.209-7.022 7.589a3.672 3.672 0 011.044 2.848c0 2.056-.019 3.715-.019 4.219 0 .411.277.89 1.057.74A15.382 15.382 0 0015.378.001z" data-name="Path 224" fill="#51504f" fill-rule="evenodd"></path> |
| </svg> |
| |
| <span class="bodytext__medium--brownish-grey">Suggest a change on this page</span> |
| </button> |
| </a> |
| </div> |
| |
| |
| </div> |
| |
| |
| |
| |
| <footer> |
| <div class="footer-section footer-section__media-section"> |
| <div class="d-flex align-items-center"> |
| |
| <a class="footer-section__media-section--link" target="_blank" href="https://github.com/apache/airflow"> |
| <svg xmlns="http://www.w3.org/2000/svg" width="46.14" height="45" viewBox="0 0 46.14 45"> |
| <path id="Path_207" d="M228.962 1078.578a23.072 23.072 0 0 0-7.29 44.96c1.154.212 1.574-.5 1.574-1.112 0-.548-.02-2-.031-3.924-6.417 1.394-7.771-3.093-7.771-3.093a6.109 6.109 0 0 0-2.562-3.375c-2.095-1.431.159-1.4.159-1.4a4.846 4.846 0 0 1 3.533 2.377c2.058 3.525 5.4 2.507 6.714 1.917a4.926 4.926 0 0 1 1.464-3.084c-5.123-.582-10.508-2.562-10.508-11.4a8.919 8.919 0 0 1 2.374-6.191 8.3 8.3 0 0 1 .226-6.105s1.937-.62 6.344 2.365a21.857 21.857 0 0 1 11.551 0c4.4-2.985 6.338-2.365 6.338-2.365a8.284 8.284 0 0 1 .23 6.105 8.9 8.9 0 0 1 2.371 6.191c0 8.862-5.393 10.812-10.533 11.384a5.506 5.506 0 0 1 1.566 4.272c0 3.084-.028 5.572-.028 6.329 0 .617.415 1.334 1.586 1.109a23.073 23.073 0 0 0-7.308-44.958z" fill="#fff" fill-rule="evenodd" data-name="Path 207" transform="translate(-205.894 -1078.578)"></path> |
| </svg> |
| |
| </a> |
| |
| <a class="footer-section__media-section--link" target="_blank" href="https://github.com/apache/airflow/issues"> |
| <svg xmlns="http://www.w3.org/2000/svg" width="45" height="45" viewBox="0 0 45 45"> |
| <g id="Group_210" data-name="Group 210" transform="translate(-339.789 -1315.282)"> |
| <path id="Path_218" d="M394.82 1315.282h-21.671a9.784 9.784 0 0 0 9.784 9.778h3.986v3.857a9.784 9.784 0 0 0 9.784 9.771v-21.523a1.884 1.884 0 0 0-1.883-1.883z" fill="#fff" data-name="Path 218" transform="translate(-11.914)"></path> |
| <path id="Path_219" d="M378.14 1332.072h-21.671a9.778 9.778 0 0 0 9.778 9.778h4.018v3.857a9.784 9.784 0 0 0 9.752 9.778v-21.536a1.877 1.877 0 0 0-1.877-1.877z" fill="#fff" data-name="Path 219" transform="translate(-5.957 -5.996)"></path> |
| <path id="Path_220" d="M361.46 1348.862h-21.671a9.778 9.778 0 0 0 9.778 9.778h3.992v3.857a9.778 9.778 0 0 0 9.778 9.778v-21.529a1.883 1.883 0 0 0-1.877-1.884z" fill="#fff" data-name="Path 220" transform="translate(0 -11.993)"></path> |
| </g> |
| </svg> |
| |
| </a> |
| |
| <a class="footer-section__media-section--link" target="_blank" href="https://s.apache.org/airflow-slack"> |
| <svg xmlns="http://www.w3.org/2000/svg" width="45.073" height="45.073" viewBox="0 0 45.073 45.073"> |
| <g id="Group_208" data-name="Group 208" transform="translate(-661.145 -806.287)"> |
| <g id="Group_204" data-name="Group 204" transform="translate(661.145 830.01)"> |
| <path id="Path_208" d="M670.634 856.859a4.744 4.744 0 1 1-4.744-4.744h4.744z" fill="#fff" data-name="Path 208" transform="translate(-661.145 -852.115)"></path> |
| <path id="Path_209" d="M684.059 856.859a4.744 4.744 0 0 1 9.489 0v11.861a4.744 4.744 0 1 1-9.489 0z" fill="#fff" data-name="Path 209" transform="translate(-672.198 -852.115)"></path> |
| </g> |
| <g id="Group_205" data-name="Group 205" transform="translate(661.145 806.287)"> |
| <path id="Path_210" d="M688.8 815.776a4.744 4.744 0 1 1 4.744-4.745v4.745z" fill="#fff" data-name="Path 210" transform="translate(-672.198 -806.287)"></path> |
| <path id="Path_211" d="M677.751 829.2a4.744 4.744 0 0 1 0 9.489H665.89a4.744 4.744 0 1 1 0-9.489z" fill="#fff" data-name="Path 211" transform="translate(-661.145 -817.34)"></path> |
| </g> |
| <g id="Group_206" data-name="Group 206" transform="translate(684.868 806.287)"> |
| <path id="Path_212" d="M729.887 833.945a4.744 4.744 0 1 1 4.745 4.745h-4.745z" fill="#fff" data-name="Path 212" transform="translate(-718.026 -817.34)"></path> |
| <path id="Path_213" d="M716.462 822.893a4.744 4.744 0 1 1-9.489 0v-11.862a4.744 4.744 0 0 1 9.489 0z" fill="#fff" data-name="Path 213" transform="translate(-706.973 -806.287)"></path> |
| </g> |
| <g id="Group_207" data-name="Group 207" transform="translate(684.868 830.01)"> |
| <path id="Path_214" d="M711.718 875.029a4.744 4.744 0 1 1-4.745 4.744v-4.744z" fill="#fff" data-name="Path 214" transform="translate(-706.973 -863.168)"></path> |
| <path id="Path_215" d="M711.718 861.6a4.744 4.744 0 1 1 0-9.489h11.861a4.744 4.744 0 0 1 0 9.489z" fill="#fff" data-name="Path 215" transform="translate(-706.973 -852.115)"></path> |
| </g> |
| </g> |
| </svg> |
| |
| </a> |
| |
| <a class="footer-section__media-section--link" target="_blank" href="https://stackoverflow.com/questions/tagged/airflow"> |
| <svg xmlns="http://www.w3.org/2000/svg" width="37.647" height="44.6" viewBox="0 0 37.647 44.6"> |
| <g id="Group_209" data-name="Group 209" transform="translate(-645.2 -975.455)"> |
| <path id="Path_216" d="M677.028 1043.1v-11.948h3.966v15.914H645.2v-15.914h3.966v11.948z" fill="#fff" data-name="Path 216" transform="translate(0 -27.014)"></path> |
| <path id="Path_217" d="M661.012 1003.008l19.467 4.069.824-3.914-19.467-4.069zm2.575-9.27l18.025 8.395 1.648-3.605-18.025-8.446zm5-8.858l15.3 12.721 2.524-3.039-15.3-12.721zm9.888-9.425l-3.193 2.369 11.845 15.965 3.193-2.369zm-17.875 36.617h19.879v-3.966H660.6z" fill="#fff" data-name="Path 217" transform="translate(-7.469)"></path> |
| </g> |
| </svg> |
| |
| </a> |
| |
| <a class="footer-section__media-section--link" target="_blank" href="https://twitter.com/ApacheAirflow"> |
| <svg xmlns="http://www.w3.org/2000/svg" width="44.355" height="44.355" viewBox="0 0 44.355 44.355"> |
| <g id="Group_211" data-name="Group 211" transform="translate(-503 -1382.2)"> |
| <path id="Path_221" d="M541.811 1382.2h-33.267a5.546 5.546 0 0 0-5.544 5.544v33.266a5.547 5.547 0 0 0 5.544 5.545h33.267a5.546 5.546 0 0 0 5.544-5.545v-33.266a5.546 5.546 0 0 0-5.544-5.544zm-5.611 16.533c.011.244.011.488.011.732 0 7.507-5.722 16.178-16.179 16.178a16.173 16.173 0 0 1-8.7-2.539 10.92 10.92 0 0 0 1.353.078 11.4 11.4 0 0 0 7.064-2.44 5.685 5.685 0 0 1-5.311-3.947 5.725 5.725 0 0 0 2.561-.1 5.7 5.7 0 0 1-4.557-5.578v-.078a5.752 5.752 0 0 0 2.572.71 5.709 5.709 0 0 1-1.763-7.6 16.146 16.146 0 0 0 11.721 5.944 6.282 6.282 0 0 1-.144-1.3 5.688 5.688 0 0 1 9.836-3.892 11.3 11.3 0 0 0 3.615-1.375 5.721 5.721 0 0 1-2.506 3.149 11.538 11.538 0 0 0 3.271-.9 11.585 11.585 0 0 1-2.844 2.958z" fill="#fff" data-name="Path 221"></path> |
| </g> |
| </svg> |
| |
| </a> |
| |
| <a class="footer-section__media-section--link" target="_blank" href="https://www.youtube.com/channel/UCSXwxpWZQ7XZ1WL3wqevChA"> |
| <svg xmlns="http://www.w3.org/2000/svg" width="49.594" height="34.941" viewBox="0 0 49.594 34.941"> |
| <path id="Path_223" d="M1124.557 1230a6.232 6.232 0 0 0-4.385-4.413c-3.867-1.043-19.376-1.043-19.376-1.043s-15.508 0-19.376 1.043a6.232 6.232 0 0 0-4.385 4.413c-1.036 3.893-1.036 12.014-1.036 12.014s0 8.122 1.036 12.015a6.232 6.232 0 0 0 4.385 4.413c3.867 1.043 19.376 1.043 19.376 1.043s15.509 0 19.376-1.043a6.232 6.232 0 0 0 4.385-4.413c1.036-3.893 1.036-12.015 1.036-12.015s.001-8.123-1.036-12.014zm-28.833 19.388v-14.748l12.962 7.374z" fill="#fff" data-name="Path 223" transform="translate(-1076 -1224.542)"></path> |
| </svg> |
| |
| </a> |
| |
| </div> |
| |
| |
| <div class="footer-section__media-section--button-with-text"> |
| <span class="footer-section__media-section--text">Want to be a part of Apache Airflow?</span> |
| <a href="/community"> |
| |
| <button id="" class="btn-filled bodytext__medium--white ">Join community</button> |
| |
| </a> |
| </div> |
| |
| |
| </div> |
| <div class="footer-section footer-section__policies-section"> |
| <div class="footer-section"> |
| <span>© The Apache Software Foundation <script>document.write(new Date().getFullYear())</script></span> |
| <div class="footer-section__policies-section--policies"> |
| |
| <a href="https://www.apache.org/licenses/" class="footer-section__policies-section--policy-item"> |
| <span>License</span> |
| </a> |
| |
| <a href="https://www.apache.org/foundation/sponsorship.html" class="footer-section__policies-section--policy-item"> |
| <span>Donate</span> |
| </a> |
| |
| <a href="https://www.apache.org/foundation/thanks.html" class="footer-section__policies-section--policy-item"> |
| <span>Thanks</span> |
| </a> |
| |
| <a href="https://www.apache.org/security/" class="footer-section__policies-section--policy-item"> |
| <span>Security</span> |
| </a> |
| |
| |
| </div> |
| </div> |
| <span class="footer-section__policies-section--disclaimer"> |
| Apache Airflow, Apache, Airflow, the Airflow logo, and the Apache feather logo are either registered trademarks or trademarks of The Apache Software Foundation. |
| All other products or name brands are trademarks of their respective holders, including The Apache Software Foundation. |
| </span> |
| </div> |
| </footer> |
| <script type="text/javascript" src="_static/_gen/js/docs.js"></script> |
| <script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script> |
| <script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script> |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script> |
| <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script> |
| <script src="_static/jquery.js"></script> |
| <script src="_static/underscore.js"></script> |
| <script src="_static/doctools.js"></script> |
| <script src="_static/clipboard.min.js"></script> |
| <script src="_static/copybutton.js"></script> |
| <script src="_static/gh-jira-links.js"></script> |
| </body> |
| </html> |