Graphs in Callback Not Updating When Using Docker Compose

I am using docker compose to launch a MongoDB and then my front end Dash. When launching locally outside of the docker-compose the graphs will update as my data in the database updates, however when using docker compose this does not happen.

What I have found is that I have two functions of my date slider and my version selection that get their data from a global variable that is defined outside their functions and this works as expected, however the graphs define their data from inside their function and do not update as the data does.

See below my docker files and some examples of the code:

docker-compose:

version: '3.7'

services:
  db:
    image: "mongo:3.4.21-xenial"
    container_name: "jmongo_db"
    restart: always
    ports:
      - "27017:27017"
  frontend:
    image: frontend:version-1.0.0
    restart: always
    volumes:
      - "/data_ssd/r:/data_ssd/r"
    depends_on:
      - db
    ports:
      - "8050:8050"

Dockerfile:

FROM python:3.7

RUN useradd -ms /bin/bash product

ADD /src /src
ADD requirements.txt .
ADD docker-entrypoint.sh .
ADD scripts/execute-etl.sh .
RUN chmod +x /docker-entrypoint.sh
RUN chmod +x /execute-etl.sh
RUN touch /var/log/cron.log

RUN pip3 install -r requirements.txt

# Add AWS stuff inside docker
RUN curl -L https://packagecloud.io/segment/aws-okta/gpgkey | apt-key add -
ADD aws_config/segment_aws-okta.list /etc/apt/sources.list.d/segment_aws-okta.list
COPY system_requirements.txt .
RUN apt-get update \
    && cat system_requirements.txt | xargs apt-get install -y \
    && rm -rf /var/lib/apt/lists/*
ADD aws_config/config /home/product/.aws/config
ENV PYTHONPATH "${PYTHONPATH}:/src/:/product_metrics/"

EXPOSE 8050

ENTRYPOINT ["/docker-entrypoint.sh"]

docker_entrypoint.sh

#!/bin/bash
set -e

echo "Product Metrics Dashboard"

if [[ "$@" = "--shell" ]]
then
    echo "Going to run bash.";
    exec "/bin/bash"
else
    echo "Dashboard"
    pushd "/src/product_metrics/frontend/"
    exec stdbuf -o L -e L python3 /src/product_metrics/frontend/ldn_cartest_metrics.py
    popd
fi

Example Code that WORKS:

SW_VERSION_OPTIONS = [{'label': SW_VERSIONS[i], 'value': SW_VERSIONS[i]} for i in range(0, len(SW_VERSIONS))]
DATE_RANGE = conn.find_date_range()
...
...
...
                        dcc.RangeSlider(
                            id="date_slider",
                            min=DATE_RANGE[0],
                            max=DATE_RANGE[1],
                            value=[DATE_RANGE[0], DATE_RANGE[1]],
                            allowCross=False,
                            className="dcc_control",
                        ),
                        html.Div(id='output-container-range-slider'),
                        html.P("Filter by Release Version:", className="control_label"),
                        dcc.RadioItems(
                            id="release_selector",
                            options=[
                                {"label": "All ", "value": "all"},
                            ],
...
...
...
# Slider Display
@app.callback(
    dash.dependencies.Output("output-container-range-slider", 'children'),
    [dash.dependencies.Input('date_slider', 'value')])
def update_output(value):
    return f'You have selected date range: {[datetime.fromtimestamp(i).strftime("%d-%m-%Y") for i in value]}'

# Button on selection pannel
@app.callback(dash.dependencies.Output("release_version", "value"),
              [dash.dependencies.Input("release_selector", "value")])
def mass_release_selection(selector):
    if selector == "all":
        return SW_VERSIONS

Example code that DOES NOT WORK:

                        html.Div(
                            [dcc.Graph(id="planned_vs_unplanned_graph")],
                            id="count_graph",
                            className="pretty_container",
                        ),
...
...
...
@app.callback(
    dash.dependencies.Output('planned_vs_unplanned_graph', 'figure'),
    [dash.dependencies.Input('date_slider', 'value'),
     dash.dependencies.Input('release_version', 'value')])
def total_disengagements(date_range, releases):
    df = conn.planned_vs_unplanned()
    dff = filter_dataframe(df, releases, date_range)
    layout_aggregate = copy.deepcopy(layout)

    x_axis = dff['ticket']
    data = [
        dict(
            type="bar",
            name="Planned",
            x=x_axis,
            y=dff['planned_count'],
            line=dict(shape="spline", smoothing="2", color="#F9ADA0"),
        ),
        dict(
            type="bar",
            name="Unplanned ",
            x=x_axis,
            y=dff["unplanned_count"],
            line=dict(shape="spline", smoothing="2", color="#849E68"),
        ),
    ]
    layout_aggregate["title"] = "Planned vs Unplanned"

    figure = dict(data=data, layout=layout_aggregate)
    return figure
1 Like

Hey,

Did you get this to work? I seem to have stuck with the same issue and can’t find any resources to fix it.

Thanks

1 Like

I really need some answer to this. Any update?

It does not make any sense. Inside my @app.callback I call my own flask server with a host named by the docker image. My flask server receives this request, there is no IP/host whatever error. I can print if I like the json response with the needed data. But my dash application keeps on saying:

“requests.exceptions.ConnectionError: HTTPConnectionPool(host=‘http’, port=80): Max retries exceeded with url: //backend_example:5000/getSomeData?dataPar=2353245345 (Caused by NewConnectionError(’<urllib3.connection.HTTPConnection object at 0x7fya83c2730>: Failed to establish a new connection: [Errno -5] No address associated with hostname’))”

My the backend is just fine, Dash is just thinking there is an error?