blob: ca0cb7474141ea4e5f87e8df0c5c29fc8c6a8502 [file] [log] [blame]
{"version":3,"sources":["webpack:///./src/pages/docs/installation/alerts_reports.mdx"],"names":["_frontmatter","layoutProps","MDXLayout","DefaultLayout","MDXContent","components","props","mdxType","parentName","isMDXComponent"],"mappings":"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","file":"component---src-pages-docs-installation-alerts-reports-mdx-ea0e95ffcdc4e8f0f159.js","sourcesContent":["import * as React from 'react'\n /* @jsx mdx */\nimport { mdx } from '@mdx-js/react';\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\n\nimport DefaultLayout from \"/home/runner/work/superset/superset/docs/node_modules/gatsby-theme-docz/src/base/Layout.js\";\nexport const _frontmatter = {};\nconst layoutProps = {\n _frontmatter\n};\nconst MDXLayout = DefaultLayout;\nexport default function MDXContent({\n components,\n ...props\n}) {\n return <MDXLayout {...layoutProps} {...props} components={components} mdxType=\"MDXLayout\">\n\n\n <h2 {...{\n \"id\": \"alerts-and-reports\"\n }}>{`Alerts and Reports`}</h2>\n <p>{`(version 1.0.1 and above)`}</p>\n <p>{`Users can configure automated alerts and reports to send dashboards or charts to an email recipient or Slack channel.`}</p>\n <ul>\n <li parentName=\"ul\">{`Alerts are sent when a SQL condition is reached`}</li>\n <li parentName=\"ul\">{`Reports are sent on a schedule`}</li>\n </ul>\n <p>{`Alerts and reports are disabled by default. To turn them on, you need to do some setup, described here.`}</p>\n <h3 {...{\n \"id\": \"requirements\"\n }}>{`Requirements`}</h3>\n <h4 {...{\n \"id\": \"commons\"\n }}>{`Commons`}</h4>\n <h5 {...{\n \"id\": \"in-your-superset_configpy\"\n }}>{`In your `}<inlineCode parentName=\"h5\">{`superset_config.py`}</inlineCode></h5>\n <ul>\n <li parentName=\"ul\"><inlineCode parentName=\"li\">{`\"ALERT_REPORTS\"`}</inlineCode>{` feature flag must be turned to True.`}</li>\n <li parentName=\"ul\"><inlineCode parentName=\"li\">{`CELERYBEAT_SCHEDULE`}</inlineCode>{` in CeleryConfig must contain schedule for `}<inlineCode parentName=\"li\">{`reports.scheduler`}</inlineCode>{`.`}</li>\n <li parentName=\"ul\">{`At least one of those must be configured, depending on what you want to use:`}\n <ul parentName=\"li\">\n <li parentName=\"ul\">{`emails: `}<inlineCode parentName=\"li\">{`SMTP_*`}</inlineCode>{` settings`}</li>\n <li parentName=\"ul\">{`Slack messages: `}<inlineCode parentName=\"li\">{`SLACK_API_TOKEN`}</inlineCode></li>\n </ul>\n </li>\n </ul>\n <h5 {...{\n \"id\": \"in-your-dockerfile\"\n }}>{`In your `}<inlineCode parentName=\"h5\">{`Dockerfile`}</inlineCode></h5>\n <ul>\n <li parentName=\"ul\">{`You must install a headless browser, for taking screenshots of the charts and dashboards. Only Firefox and Chrome are currently supported.`}\n <blockquote parentName=\"li\">\n <p parentName=\"blockquote\">{`If you choose Chrome, you must also change the value of `}<inlineCode parentName=\"p\">{`WEBDRIVER_TYPE`}</inlineCode>{` to `}<inlineCode parentName=\"p\">{`\"chrome\"`}</inlineCode>{` in your `}<inlineCode parentName=\"p\">{`superset_config.py`}</inlineCode>{`.`}</p>\n </blockquote>\n </li>\n </ul>\n <h4 {...{\n \"id\": \"slack-integration\"\n }}>{`Slack integration`}</h4>\n <p>{`To send alerts and reports to Slack channels, you need to create a new Slack Application on your workspace.`}</p>\n <ol>\n <li parentName=\"ol\">{`Connect to your Slack workspace, then head to `}<a parentName=\"li\" {...{\n \"href\": \"https://api.slack.com/apps\"\n }}>{`https://api.slack.com/apps`}</a>{`.`}</li>\n <li parentName=\"ol\">{`Create a new app.`}</li>\n <li parentName=\"ol\">{`Go to \"OAuth & Permissions\" section, and give the following scopes to your app:`}\n <ul parentName=\"li\">\n <li parentName=\"ul\"><inlineCode parentName=\"li\">{`incoming-webhook`}</inlineCode></li>\n <li parentName=\"ul\"><inlineCode parentName=\"li\">{`files:write`}</inlineCode></li>\n </ul>\n </li>\n <li parentName=\"ol\">{`At the top of the \"OAuth and Permissions\" section, click \"install to workspace\".`}</li>\n <li parentName=\"ol\">{`Select a default channel for your app and continue.\n(You can post to any channel by inviting your Superset app into that channel).`}</li>\n <li parentName=\"ol\">{`The app should now be installed in your workspace, and a \"Bot User OAuth Access Token\" should have been created. Copy that token in the `}<inlineCode parentName=\"li\">{`SLACK_API_TOKEN`}</inlineCode>{` variable of your `}<inlineCode parentName=\"li\">{`superset_config.py`}</inlineCode>{`.`}</li>\n <li parentName=\"ol\">{`Restart the service (or run `}<inlineCode parentName=\"li\">{`superset init`}</inlineCode>{`) to pull in the new configuration.`}</li>\n </ol>\n <p>{`Note: when you configure an alert or a report, the Slack channel list take channel names without the leading '#' e.g. use `}<inlineCode parentName=\"p\">{`alerts`}</inlineCode>{` instead of `}<inlineCode parentName=\"p\">{`#alerts`}</inlineCode>{`.`}</p>\n <h4 {...{\n \"id\": \"kubernetes-specific\"\n }}>{`Kubernetes specific`}</h4>\n <ul>\n <li parentName=\"ul\">{`You must have a `}<inlineCode parentName=\"li\">{`celery beat`}</inlineCode>{` pod running. If you're using the chart included in the GitHub repository under `}<a parentName=\"li\" {...{\n \"href\": \"https://github.com/apache/superset/tree/master/helm/superset\"\n }}>{`helm/superset`}</a>{`, you need to put `}<inlineCode parentName=\"li\">{`supersetCeleryBeat.enabled = true`}</inlineCode>{` in your values override.`}</li>\n <li parentName=\"ul\">{`You can see the dedicated docs about `}<a parentName=\"li\" {...{\n \"href\": \"/docs/installation/running-on-kubernetes\"\n }}>{`Kubernetes installation`}</a>{` for more generic details.`}</li>\n </ul>\n <h4 {...{\n \"id\": \"docker-compose-specific\"\n }}>{`Docker-compose specific`}</h4>\n <h5 {...{\n \"id\": \"you-must-have-in-yourdocker-composeyaml\"\n }}>{`You must have in your`}<inlineCode parentName=\"h5\">{`docker-compose.yaml`}</inlineCode></h5>\n <ul>\n <li parentName=\"ul\">{`a redis message broker`}</li>\n <li parentName=\"ul\">{`PostgreSQL DB instead of SQLlite`}</li>\n <li parentName=\"ul\">{`one or more `}<inlineCode parentName=\"li\">{`celery worker`}</inlineCode></li>\n <li parentName=\"ul\">{`a single `}<inlineCode parentName=\"li\">{`celery beat`}</inlineCode></li>\n </ul>\n <h3 {...{\n \"id\": \"detailed-config\"\n }}>{`Detailed config`}</h3>\n <p>{`The following configurations need to be added to the `}<inlineCode parentName=\"p\">{`superset_config.py`}</inlineCode>{` file. This file is loaded when the image runs, and any configurations in it will override the default configurations found in the `}<inlineCode parentName=\"p\">{`config.py`}</inlineCode>{`.`}</p>\n <p>{`You can find documentation about each field in the default `}<inlineCode parentName=\"p\">{`config.py`}</inlineCode>{` in the GitHub repository under `}<a parentName=\"p\" {...{\n \"href\": \"https://github.com/apache/superset/blob/master/superset/config.py\"\n }}>{`superset/config.py`}</a>{`.`}</p>\n <p>{`You need to replace default values with your custom Redis, Slack and/or SMTP config.`}</p>\n <p>{`In the `}<inlineCode parentName=\"p\">{`CeleryConfig`}</inlineCode>{`, only the `}<inlineCode parentName=\"p\">{`CELERYBEAT_SCHEDULE`}</inlineCode>{` is relative to this feature, the rest of the `}<inlineCode parentName=\"p\">{`CeleryConfig`}</inlineCode>{` can be changed for your needs.`}</p>\n <pre><code parentName=\"pre\" {...{\n \"className\": \"language-python\"\n }}>{`from celery.schedules import crontab\n\nFEATURE_FLAGS = {\n \"ALERT_REPORTS\": True\n}\n\nREDIS_HOST = \"redis-superset\"\nREDIS_PORT = \"6379\"\n\nclass CeleryConfig:\n BROKER_URL = 'redis://%s:%s/0' % (REDIS_HOST, REDIS_PORT)\n CELERY_IMPORTS = ('superset.sql_lab', \"superset.tasks\", \"superset.tasks.thumbnails\", )\n CELERY_RESULT_BACKEND = 'redis://%s:%s/0' % (REDIS_HOST, REDIS_PORT)\n CELERYD_PREFETCH_MULTIPLIER = 10\n CELERY_ACKS_LATE = True\n CELERY_ANNOTATIONS = {\n 'sql_lab.get_sql_results': {\n 'rate_limit': '100/s',\n },\n 'email_reports.send': {\n 'rate_limit': '1/s',\n 'time_limit': 600,\n 'soft_time_limit': 600,\n 'ignore_result': True,\n },\n }\n CELERYBEAT_SCHEDULE = {\n 'reports.scheduler': {\n 'task': 'reports.scheduler',\n 'schedule': crontab(minute='*', hour='*'),\n },\n 'reports.prune_log': {\n 'task': 'reports.prune_log',\n 'schedule': crontab(minute=0, hour=0),\n },\n }\nCELERY_CONFIG = CeleryConfig\n\nSCREENSHOT_LOCATE_WAIT = 100\nSCREENSHOT_LOAD_WAIT = 600\n\n# Slack configuration\nSLACK_API_TOKEN = \"xoxb-\"\n\n# Email configuration\nSMTP_HOST = \"smtp.sendgrid.net\" #change to your host\nSMTP_STARTTLS = True\nSMTP_SSL = False\nSMTP_USER = \"your_user\"\nSMTP_PORT = 2525 # your port eg. 587\nSMTP_PASSWORD = \"your_password\"\nSMTP_MAIL_FROM = \"noreply@youremail.com\"\n\n# WebDriver configuration\n# If you use Firefox, you can stick with default values\n# If you use Chrome, then add the following WEBDRIVER_TYPE and WEBDRIVER_OPTION_ARGS\nWEBDRIVER_TYPE = \"chrome\"\nWEBDRIVER_OPTION_ARGS = [\n \"--force-device-scale-factor=2.0\",\n \"--high-dpi-support=2.0\",\n \"--headless\",\n \"--disable-gpu\",\n \"--disable-dev-shm-usage\",\n \"--no-sandbox\",\n \"--disable-setuid-sandbox\",\n \"--disable-extensions\",\n]\n\n# This is for internal use, you can keep http\nWEBDRIVER_BASEURL=\"http://superset:8088\"\n# This is the link sent to the recipient, change to your domain eg. https://superset.mydomain.com\nWEBDRIVER_BASEURL_USER_FRIENDLY=\"http://localhost:8088\"\n`}</code></pre>\n <h3 {...{\n \"id\": \"custom-dockerfile\"\n }}>{`Custom Dockerfile`}</h3>\n <p>{`A webdriver (and headless browser) is needed to capture screenshots of the charts and dashboards which are then sent to the recipient. As the base superset image does not have a webdriver installed, we need to extend it and install the webdriver.`}</p>\n <h4 {...{\n \"id\": \"using-firefox\"\n }}>{`Using Firefox`}</h4>\n <pre><code parentName=\"pre\" {...{\n \"className\": \"language-docker\"\n }}>{`FROM apache/superset:1.0.1\n\nUSER root\n\nRUN apt-get update && \\\\\n apt-get install --no-install-recommends -y firefox-esr\n\nENV GECKODRIVER_VERSION=0.29.0\nRUN wget -q https://github.com/mozilla/geckodriver/releases/download/v\\${GECKODRIVER_VERSION}/geckodriver-v\\${GECKODRIVER_VERSION}-linux64.tar.gz && \\\\\n tar -x geckodriver -zf geckodriver-v\\${GECKODRIVER_VERSION}-linux64.tar.gz -O > /usr/bin/geckodriver && \\\\\n chmod 755 /usr/bin/geckodriver && \\\\\n rm geckodriver-v\\${GECKODRIVER_VERSION}-linux64.tar.gz\n\nRUN pip install --no-cache gevent psycopg2 redis\n\nUSER superset\n`}</code></pre>\n <h4 {...{\n \"id\": \"using-chrome\"\n }}>{`Using Chrome`}</h4>\n <pre><code parentName=\"pre\" {...{\n \"className\": \"language-docker\"\n }}>{`FROM apache/superset:1.0.1\n\nUSER root\n\nRUN apt-get update && \\\\\n wget -q https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb && \\\\\n apt-get install -y --no-install-recommends ./google-chrome-stable_current_amd64.deb && \\\\\n rm -f google-chrome-stable_current_amd64.deb\n\nRUN export CHROMEDRIVER_VERSION=$(curl --silent https://chromedriver.storage.googleapis.com/LATEST_RELEASE_88) && \\\\\n wget -q https://chromedriver.storage.googleapis.com/\\${CHROMEDRIVER_VERSION}/chromedriver_linux64.zip && \\\\\n unzip chromedriver_linux64.zip -d /usr/bin && \\\\\n chmod 755 /usr/bin/chromedriver && \\\\\n rm -f chromedriver_linux64.zip\n\nRUN pip install --no-cache gevent psycopg2 redis\n\nUSER superset\n`}</code></pre>\n <blockquote>\n <p parentName=\"blockquote\">{`Don't forget to set `}<inlineCode parentName=\"p\">{`WEBDRIVER_TYPE`}</inlineCode>{` and `}<inlineCode parentName=\"p\">{`WEBDRIVER_OPTION_ARGS`}</inlineCode>{` in your config if you use Chrome.`}</p>\n </blockquote>\n <h3 {...{\n \"id\": \"summary-of-steps-to-turn-on-alerts-and-reporting\"\n }}>{`Summary of steps to turn on alerts and reporting:`}</h3>\n <p>{`Using the templates below,`}</p>\n <ol>\n <li parentName=\"ol\">{`Create a new directory and create the Dockerfile`}</li>\n <li parentName=\"ol\">{`Build the extended image using the Dockerfile`}</li>\n <li parentName=\"ol\">{`Create the `}<inlineCode parentName=\"li\">{`docker-compose.yaml`}</inlineCode>{` file in the same directory`}</li>\n <li parentName=\"ol\">{`Create a new subdirectory called `}<inlineCode parentName=\"li\">{`config`}</inlineCode></li>\n <li parentName=\"ol\">{`Create the `}<inlineCode parentName=\"li\">{`superset_config.py`}</inlineCode>{` file in the `}<inlineCode parentName=\"li\">{`config`}</inlineCode>{` subdirectory`}</li>\n <li parentName=\"ol\">{`Run the image using `}<inlineCode parentName=\"li\">{`docker-compose up`}</inlineCode>{` in the same directory as the `}<inlineCode parentName=\"li\">{`docker-compose.py`}</inlineCode>{` file`}</li>\n <li parentName=\"ol\">{`In a new terminal window, upgrade the DB by running `}<inlineCode parentName=\"li\">{`docker exec -it superset-1.0.1-extended superset db upgrade`}</inlineCode></li>\n <li parentName=\"ol\">{`Then run `}<inlineCode parentName=\"li\">{`docker exec -it superset-1.0.1-extended superset init`}</inlineCode></li>\n <li parentName=\"ol\">{`Then setup your admin user if need be, `}<inlineCode parentName=\"li\">{`docker exec -it superset-1.0.1-extended superset fab create-admin`}</inlineCode></li>\n <li parentName=\"ol\">{`Finally, restart the running instance - `}<inlineCode parentName=\"li\">{`CTRL-C`}</inlineCode>{`, then `}<inlineCode parentName=\"li\">{`docker-compose up`}</inlineCode></li>\n </ol>\n <p>{`(note: v 1.0.1 is current at time of writing, you can change the version number to the latest version if a newer version is available)`}</p>\n <h3 {...{\n \"id\": \"docker-compose\"\n }}>{`Docker compose`}</h3>\n <p>{`The docker compose file lists the services that will be used when running the image. The specific services needed for alerts and reporting are outlined below.`}</p>\n <h4 {...{\n \"id\": \"redis-message-broker\"\n }}>{`Redis message broker`}</h4>\n <p>{`To ferry requests between the celery worker and the Superset instance, we use a message broker. This template uses Redis.`}</p>\n <h4 {...{\n \"id\": \"replacing-sqlite-with-postgres\"\n }}>{`Replacing SQLite with Postgres`}</h4>\n <p>{`While it might be possible to use SQLite for alerts and reporting, it is highly recommended using a more production ready DB for Superset in general. Our template uses Postgres.`}</p>\n <h4 {...{\n \"id\": \"celery-worker\"\n }}>{`Celery worker`}</h4>\n <p>{`The worker will process the tasks that need to be performed when an alert or report is fired.`}</p>\n <h4 {...{\n \"id\": \"celery-beat\"\n }}>{`Celery beat`}</h4>\n <p>{`The beat is the scheduler that tells the worker when to perform its tasks. This schedule is defined when you create the alert or report.`}</p>\n <h4 {...{\n \"id\": \"full-docker-composeyaml-configuration\"\n }}>{`Full `}<inlineCode parentName=\"h4\">{`docker-compose.yaml`}</inlineCode>{` configuration`}</h4>\n <p>{`The Redis, Postgres, Celery worker and Celery beat services are defined in the template:`}</p>\n <p>{`Config for `}<inlineCode parentName=\"p\">{`docker-compose.yaml`}</inlineCode>{`:`}</p>\n <pre><code parentName=\"pre\" {...{\n \"className\": \"language-docker\"\n }}>{`version: '3.6'\nservices:\n redis:\n image: redis:6.0.9-buster\n restart: on-failure\n volumes:\n - redis:/data\n postgres:\n image: postgres\n restart: on-failure\n environment:\n POSTGRES_DB: superset\n POSTGRES_PASSWORD: superset\n POSTGRES_USER: superset\n volumes:\n - db:/var/lib/postgresql/data\n worker:\n image: superset-1.0.1-extended\n restart: on-failure\n healthcheck:\n disable: true\n depends_on:\n - superset\n - postgres\n - redis\n command: \"celery --app=superset.tasks.celery_app:app worker --pool=gevent --concurrency=500\"\n volumes:\n - ./config/:/app/pythonpath/\n beat:\n image: superset-1.0.1-extended\n restart: on-failure\n healthcheck:\n disable: true\n depends_on:\n - superset\n - postgres\n - redis\n command: \"celery --app=superset.tasks.celery_app:app beat --pidfile /tmp/celerybeat.pid --schedule /tmp/celerybeat-schedule\"\n volumes:\n - ./config/:/app/pythonpath/\n superset:\n image: superset-1.0.1-extended\n restart: on-failure\n environment:\n - SUPERSET_PORT=8088\n ports:\n - \"8088:8088\"\n depends_on:\n - postgres\n - redis\n command: gunicorn --bind 0.0.0.0:8088 --access-logfile - --error-logfile - --workers 5 --worker-class gthread --threads 4 --timeout 200 --limit-request-line 4094 --limit-request-field_size 8190 superset.app:create_app()\n volumes:\n - ./config/:/app/pythonpath/\nvolumes:\n db:\n external: true\n redis:\n external: false\n`}</code></pre>\n <h3 {...{\n \"id\": \"summary\"\n }}>{`Summary`}</h3>\n <p>{`With the extended image created by using the `}<inlineCode parentName=\"p\">{`Dockerfile`}</inlineCode>{`, and then running that image using `}<inlineCode parentName=\"p\">{`docker-compose.yaml`}</inlineCode>{`, plus the required configurations in the `}<inlineCode parentName=\"p\">{`superset_config.py`}</inlineCode>{` you should now have alerts and reporting working correctly.`}</p>\n <ul>\n <li parentName=\"ul\">{`The above templates also work in a Docker swarm environment, you would just need to add `}<inlineCode parentName=\"li\">{`Deploy:`}</inlineCode>{` to the Superset, Redis and Postgres services along with your specific configs for your swarm`}</li>\n </ul>\n <h1 {...{\n \"id\": \"old-reports-feature\"\n }}>{`Old Reports feature`}</h1>\n <h2 {...{\n \"id\": \"scheduling-and-emailing-reports\"\n }}>{`Scheduling and Emailing Reports`}</h2>\n <p>{`(version 0.38 and below)`}</p>\n <h3 {...{\n \"id\": \"email-reports\"\n }}>{`Email Reports`}</h3>\n <p>{`Email reports allow users to schedule email reports for:`}</p>\n <ul>\n <li parentName=\"ul\">{`chart and dashboard visualization (attachment or inline)`}</li>\n <li parentName=\"ul\">{`chart data (CSV attachment on inline table)`}</li>\n </ul>\n <p>{`Enable email reports in your `}<inlineCode parentName=\"p\">{`superset_config.py`}</inlineCode>{` file:`}</p>\n <pre><code parentName=\"pre\" {...{\n \"className\": \"language-python\"\n }}>{`ENABLE_SCHEDULED_EMAIL_REPORTS = True\n`}</code></pre>\n <p>{`This flag enables some permissions that are stored in your database, so you'll want to run `}<inlineCode parentName=\"p\">{`superset init`}</inlineCode>{` again if you are running this in a dev environment.\nNow you will find two new items in the navigation bar that allow you to schedule email reports:`}</p>\n <ul>\n <li parentName=\"ul\"><strong parentName=\"li\">{`Manage > Dashboard Emails`}</strong></li>\n <li parentName=\"ul\"><strong parentName=\"li\">{`Manage > Chart Email Schedules`}</strong></li>\n </ul>\n <p>{`Schedules are defined in `}<a parentName=\"p\" {...{\n \"href\": \"https://crontab.guru/\"\n }}>{`crontab format`}</a>{` and each schedule can have a list\nof recipients (all of them can receive a single mail, or separate mails). For audit purposes, all\noutgoing mails can have a mandatory BCC.`}</p>\n <p>{`In order get picked up you need to configure a celery worker and a celery beat (see section above\n“Celery Tasks”). Your celery configuration also needs an entry `}<inlineCode parentName=\"p\">{`email_reports.schedule_hourly`}</inlineCode>{` for\n`}<inlineCode parentName=\"p\">{`CELERYBEAT_SCHEDULE`}</inlineCode>{`.`}</p>\n <p>{`To send emails you need to configure SMTP settings in your `}<inlineCode parentName=\"p\">{`superset_config.py`}</inlineCode>{` configuration file.`}</p>\n <pre><code parentName=\"pre\" {...{\n \"className\": \"language-python\"\n }}>{`EMAIL_NOTIFICATIONS = True\n\nSMTP_HOST = \"email-smtp.eu-west-1.amazonaws.com\"\nSMTP_STARTTLS = True\nSMTP_SSL = False\nSMTP_USER = \"smtp_username\"\nSMTP_PORT = 25\nSMTP_PASSWORD = os.environ.get(\"SMTP_PASSWORD\")\nSMTP_MAIL_FROM = \"insights@komoot.com\"\n`}</code></pre>\n <p>{`To render dashboards you need to install a local browser on your Superset instance:`}</p>\n <ul>\n <li parentName=\"ul\"><a parentName=\"li\" {...{\n \"href\": \"https://github.com/mozilla/geckodriver\"\n }}>{`geckodriver`}</a>{` for Firefox`}</li>\n <li parentName=\"ul\"><a parentName=\"li\" {...{\n \"href\": \"http://chromedriver.chromium.org/\"\n }}>{`chromedriver`}</a>{` for Chrome`}</li>\n </ul>\n <p>{`You'll need to adjust the `}<inlineCode parentName=\"p\">{`WEBDRIVER_TYPE`}</inlineCode>{` accordingly in your configuration. You also need\nto specify on behalf of which username to render the dashboards. In general dashboards and charts\nare not accessible to unauthorized requests, that is why the worker needs to take over credentials\nof an existing user to take a snapshot.`}</p>\n <pre><code parentName=\"pre\" {...{\n \"className\": \"language-python\"\n }}>{`THUMBNAIL_SELENIUM_USER = 'username_with_permission_to_access_dashboards'\n`}</code></pre>\n <p><strong parentName=\"p\">{`Important notes`}</strong></p>\n <ul>\n <li parentName=\"ul\">{`Be mindful of the concurrency setting for celery (using `}<inlineCode parentName=\"li\">{`-c 4`}</inlineCode>{`). Selenium/webdriver instances can\nconsume a lot of CPU / memory on your servers.`}</li>\n <li parentName=\"ul\">{`In some cases, if you notice a lot of leaked geckodriver processes, try running your celery\nprocesses with `}<inlineCode parentName=\"li\">{`celery worker --pool=prefork --max-tasks-per-child=128 ...`}</inlineCode></li>\n <li parentName=\"ul\">{`It is recommended to run separate workers for the `}<inlineCode parentName=\"li\">{`sql_lab`}</inlineCode>{` and `}<inlineCode parentName=\"li\">{`email_reports`}</inlineCode>{` tasks. This can be\ndone using the `}<inlineCode parentName=\"li\">{`queue`}</inlineCode>{` field in `}<inlineCode parentName=\"li\">{`CELERY_ANNOTATIONS`}</inlineCode>{`.`}</li>\n <li parentName=\"ul\">{`Adjust `}<inlineCode parentName=\"li\">{`WEBDRIVER_BASEURL`}</inlineCode>{` in your configuration file if celery workers can’t access Superset via\nits default value of `}<inlineCode parentName=\"li\">{`http://0.0.0.0:8080/`}</inlineCode>{`.`}</li>\n </ul>\n <h3 {...{\n \"id\": \"schedule-reports\"\n }}>{`Schedule Reports`}</h3>\n <p>{`You can optionally allow your users to schedule queries directly in SQL Lab. This is done by addding\nextra metadata to saved queries, which are then picked up by an external scheduled (like\n`}<a parentName=\"p\" {...{\n \"href\": \"https://airflow.apache.org/\"\n }}>{`Apache Airflow`}</a>{`).`}</p>\n <p>{`To allow scheduled queries, add the following to your configuration file:`}</p>\n <pre><code parentName=\"pre\" {...{\n \"className\": \"language-python\"\n }}>{`FEATURE_FLAGS = {\n # Configuration for scheduling queries from SQL Lab. This information is\n # collected when the user clicks \"Schedule query\", and saved into the \\`extra\\`\n # field of saved queries.\n # See: https://github.com/mozilla-services/react-jsonschema-form\n 'SCHEDULED_QUERIES': {\n 'JSONSCHEMA': {\n 'title': 'Schedule',\n 'description': (\n 'In order to schedule a query, you need to specify when it '\n 'should start running, when it should stop running, and how '\n 'often it should run. You can also optionally specify '\n 'dependencies that should be met before the query is '\n 'executed. Please read the documentation for best practices '\n 'and more information on how to specify dependencies.'\n ),\n 'type': 'object',\n 'properties': {\n 'output_table': {\n 'type': 'string',\n 'title': 'Output table name',\n },\n 'start_date': {\n 'type': 'string',\n 'title': 'Start date',\n # date-time is parsed using the chrono library, see\n # https://www.npmjs.com/package/chrono-node#usage\n 'format': 'date-time',\n 'default': 'tomorrow at 9am',\n },\n 'end_date': {\n 'type': 'string',\n 'title': 'End date',\n # date-time is parsed using the chrono library, see\n # https://www.npmjs.com/package/chrono-node#usage\n 'format': 'date-time',\n 'default': '9am in 30 days',\n },\n 'schedule_interval': {\n 'type': 'string',\n 'title': 'Schedule interval',\n },\n 'dependencies': {\n 'type': 'array',\n 'title': 'Dependencies',\n 'items': {\n 'type': 'string',\n },\n },\n },\n },\n 'UISCHEMA': {\n 'schedule_interval': {\n 'ui:placeholder': '@daily, @weekly, etc.',\n },\n 'dependencies': {\n 'ui:help': (\n 'Check the documentation for the correct format when '\n 'defining dependencies.'\n ),\n },\n },\n 'VALIDATION': [\n # ensure that start_date <= end_date\n {\n 'name': 'less_equal',\n 'arguments': ['start_date', 'end_date'],\n 'message': 'End date cannot be before start date',\n # this is where the error message is shown\n 'container': 'end_date',\n },\n ],\n # link to the scheduler; this example links to an Airflow pipeline\n # that uses the query id and the output table as its name\n 'linkback': (\n 'https://airflow.example.com/admin/airflow/tree?'\n 'dag_id=query_\\${id}_\\${extra_json.schedule_info.output_table}'\n ),\n },\n}\n`}</code></pre>\n <p>{`This feature flag is based on\n`}<a parentName=\"p\" {...{\n \"href\": \"https://github.com/mozilla-services/react-jsonschema-form\"\n }}>{`react-jsonschema-form`}</a>{` and will add a\nbutton called “Schedule Query” to SQL Lab. When the button is clicked, a modal will show up where\nthe user can add the metadata required for scheduling the query.`}</p>\n <p>{`This information can then be retrieved from the endpoint `}<inlineCode parentName=\"p\">{`/savedqueryviewapi/api/read`}</inlineCode>{` and used to\nschedule the queries that have `}<inlineCode parentName=\"p\">{`scheduled_queries`}</inlineCode>{` in their JSON metadata. For schedulers other than\nAirflow, additional fields can be easily added to the configuration file above.`}</p>\n\n </MDXLayout>;\n}\n;\nMDXContent.isMDXComponent = true;\n "],"sourceRoot":""}