> For the complete documentation index, see [llms.txt](https://docs.tonic.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.tonic.ai/app/api/example-polling-for-a-job-status-+-creating-a-docker-package.md).

# Example script: Polling for a job status and creating a Docker package

Polls for a status of a data generation job every minute while the job is running or in the queue.&#x20;

If the job fails or is canceled, an appropriate message is displayed.

If the job completes successfully, it creates a SQL dump and, if it does not already exist in the directory, a Dockerfile. The Dockerfile helps you to use Docker to distribute the destination database.

For more information, read our [blog about using Docker to manage your databases](https://www.tonic.ai/blog/using-docker-to-manage-your-test-database).

Note that the SQL dump is specific for PostgreSQL databases and uses `pg_dump`.

## Text of the script

{% tabs %}
{% tab title="Python" %}
{% code title="tonic\_status\_poll.py" overflow="wrap" %}

```python
# Note that our API does not guarantee backward compatibility.
# For the endpoints and parameters for your exact version, view the 
# Swagger API documentation that comes with your instance.
# If you use Structural Cloud, the API documentation is at:
# https://app.tonic.ai/apidocs/index.html

# Tested 2026.07.08 with Tonic API v2024.01.0

import os
import pathlib
import subprocess
import sys
import time

import requests

TONIC_BASE_URL = "http://<<STRUCTURAL HOSTNAME>>/"
TONIC_WORKSPACE_ID = "<<STRUCTURAL WORKSPACE ID>>"
TONIC_APIKEY = "<<STRUCTURAL APIKEY>>"
DESTINATION_DB_PASSWORD = "<<DESTINATION DATABASE PASSWORD>>"
PG_HOST = "<<DESTINATION DATABASE HOST>>"
PG_PORT = "<<DESTINATION DATABASE PORT>>"
PG_USER = "<<DESTINATION DATABASE USER>>"
PG_DATABASE = "<<DESTINATION DATABASE NAME>>"

class TonicSession:
    def __init__(self, base_url, apikey):
        self._base_url = base_url
        self._session = requests.Session()
        self._api_key = apikey
        self._session.headers.update({"Authorization": "Apikey {}".format(apikey)})

    def get_status(self, job_id):
        print("Grabbing job status for job {jobid}...".format(jobid=job_id))
        status_url = "{url}api/GenerateData/jobs/{job_id}".format(
            url=self._base_url, job_id=job_id
        )

        while True:
            resp = self._session.get(status_url)

            if resp.ok:
                resp_json = resp.json()
                status = resp_json.get("status")
                message = resp_json.get("errorMessages")

                if status and status in ("Running", "Queued", "Running with warnings"):
                    print(
                        "Job {job_id} is {status}. Waiting 1 minute before "
                        "checking again".format(job_id=job_id, status=status)
                    )
                    time.sleep(60)
                    print("Checking for job status again... ")
                else:
                    if status and status in ("Failed", "Canceled"):
                        print(
                            "Job {job_id} {status} with the following "
                            "message: {message}".format(
                                job_id=job_id, status=status, message=message
                            )
                        )
                    if status and status in ("Completed", "Completed with warnings"):
                        print("Job {job_id} completed.".format(job_id=job_id))
                        self.packaging_for_docker(job_id)
                    break
            else:
                return resp.raise_for_status()

    def packaging_for_docker(self, job_id):
        db_dumpfile="pg_dump_{jobid}.sql".format(jobid=job_id)

        with open(db_dumpfile, "wb") as fobj:
            os.environ["PGPASSWORD"] = DESTINATION_DB_PASSWORD
            os.environ["PGHOST"] = PG_HOST
            os.environ["PGPORT"] = PG_PORT
            os.environ["PGUSER"] = PG_USER
            os.environ["PGDATABASE"] = PG_DATABASE

            print("Dump started for {dbname}...".format(dbname=PG_DATABASE))

            pgdump_proc = subprocess.Popen(
                "pg_dump", stdout=subprocess.PIPE, universal_newlines=True
            )
            for stdout_line in iter(pgdump_proc.stdout.readline, ""):
                fobj.write(stdout_line.encode("utf-8"))
            pgdump_proc.stdout.close()

            directory = pathlib.Path(fobj.name).parent.absolute()

            if "Dockerfile" not in os.listdir(directory):
                with open("Dockerfile", "w") as dfile_obj:
                    dfile_obj.writelines(
                        [
                            "FROM postgres:13\n",
                            "COPY {db_dumpfile} /docker-entrypoint-initdb.d/".format(db_dumpfile=db_dumpfile),
                        ]
                    )
                    dfile_obj.close()

        print(
            "A SQL dump of the destination DB can be found here: {dir}/{db_dumpfile}".format(
                dir=directory, db_dumpfile=db_dumpfile
            )
        )

def main():
    tonic_job_id = sys.argv[1]
    session = TonicSession(TONIC_BASE_URL, TONIC_APIKEY)
    session.get_status(tonic_job_id)
    print("\nRun this script against another Structural job ID to poll for its status.")

if __name__ == "__main__":
    main()

```

{% endcode %}
{% endtab %}
{% endtabs %}

## Building a Docker image from the Dockerfile

To use the resulting Dockerfile to build a Docker image:

```
docker build -t <image_name:tag>
```

## Running the Docker image

To run the image, expose the database on a local port, and, if needed, add a superuser password:

{% code overflow="wrap" %}

```
docker run -d -p <local_port>:5432 --name <container_name> -e POSTGRES_PASSWORD=mysecretpassword <image_name:tag>
```

{% endcode %}

## Connecting to the database

To connect to the database:

```
psql postgres -p <local_port> -h 127.0.0.1 -U postgres
```

You are prompted for the superuser password.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.tonic.ai/app/api/example-polling-for-a-job-status-+-creating-a-docker-package.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
