Run same callback in parallel

I have developed an app which based on user input reads data from Elasticsearch and AWS S3, creates a dataframe and link to download the data when user clicks a button. Now I intend to extend the app to process the data in batches when user clicks on the button, show the progress in the UI and a download link when the data is ready.

Below is the code that I am running currently:

Add CSS stylesheet for the App layout

external_stylesheets = [‘https://codepen.io/chriddyp/pen/bWLwgP.css’]

app = dash.Dash(name, external_stylesheets = external_stylesheets)
app.config[‘suppress_callback_exceptions’] = True
server = app.server

colors = {
‘background’: ‘#808080’,
‘text’: ‘#7FDBFF
}

machine_options = {
‘GO’: [‘BAY22’, ‘BAY23’, ‘BAY24’],
‘SZ’: [‘BAY1001’, ‘BAY1002’, ‘BAY1003’, ‘BAY1004’, ‘BAY1005’,
‘BAY1006’, ‘BAY1007’, ‘BAY1008’, ‘BAY2001’, ‘BAY2002’,
‘BAY2003’, ‘BAY2004’, ‘BAY2005’, ‘BAY2006’, ‘BAY2007’,
‘BAY2008’, ‘BAY2009’, ‘BAY3001’, ‘BAY3001’, ‘BAY3002’,
‘BAY3003’, ‘BAY3004’, ‘BAY3005’, ‘BAY3006’, ‘BAY3007’,
‘BAY3008’, ‘BAY4001’, ‘BAY4002’, ‘BAY4003’, ‘BAY4004’,
‘BAY4005’, ‘BAY4006’, ‘BAY4007’, ‘BAY4008’, ‘BAY5001’,
‘BAY5002’, ‘BAY5003’, ‘BAY5004’, ‘BAY5005’, ‘BAY5006’],
‘PN’: [‘MA21’, ‘MA22’, ‘MA24’, ‘MA25’, ‘MA26’, ‘MA28’, ‘MA30’]
}

station_id_options = {
‘GO’: [‘STA01’, ‘STA02’, ‘STA03’, ‘STA04’, ‘STA05’, ‘STA06’, ‘STA07’,
‘STA08’, ‘STA09’, ‘STA10’, ‘STA11’, ‘STA12’, ‘STA13’, ‘STA14’,
‘STA15’, ‘STA16’, ‘STA17’, ‘STA18’, ‘STA19’, ‘STA20’, ‘STA21’,
‘STA22’, ‘STA23’, ‘STA24’, ‘STA25’, ‘STA26’, ‘STA27’, ‘STA28’],
‘SZ’: [‘STA01’, ‘STA02’, ‘STA03’, ‘STA04’, ‘STA05’, ‘STA06’, ‘STA07’,
‘STA08’, ‘STA09’, ‘STA10’, ‘STA11’, ‘STA12’, ‘STA13’, ‘STA14’,
‘STA15’, ‘STA16’, ‘STA17’, ‘STA18’, ‘STA19’, ‘STA20’, ‘STA21’,
‘STA22’, ‘STA23’, ‘STA24’],
‘PN’: [‘P0’, ‘P01’, ‘P02’, ‘P03’, ‘P04’, ‘P05’, ‘P06’, ‘P07’, ‘P08’, ‘P09’,
‘P10’, ‘P11’, ‘P12’, ‘P13’, ‘P14’, ‘P15’, ‘P16’, ‘P17’, ‘P18’, ‘P19’,
‘P20’, ‘P21’, ‘P22’, ‘P24’]
}

app.layout = html.Div([html.Img(src = app.get_asset_url(‘wd-banner.JPG’), style = {‘height’: ‘25%’,
‘width’: ‘100%’
}),
html.Div(html.Table([
html.Td([html.Label(‘Site’),
dcc.RadioItems(
id = ‘site’,
options = [{‘label’: k, ‘value’: k} for k in machine_options.keys()],
value = ‘GO’
)]),
html.Td([html.Label(‘Machine’),
dcc.Dropdown(
id = ‘machine_dropdown’,
multi = True)], style = {‘width’: ‘20%’}),
html.Td((html.Label(‘From Date:’),
dcc.DatePickerSingle(
id = ‘from_date’,
min_date_allowed = dt(1995, 8, 5),
max_date_allowed = dt(2099, 12, 31),
initial_visible_month = dt(int(y), int(m), int(d)),
date = str(dtm.date.today())
),
)),
html.Td((html.Label(‘To Date:’),
dcc.DatePickerSingle(
id = ‘to_date’,
min_date_allowed = dt(1995, 8, 5),
max_date_allowed = dt(2099, 12, 31),
initial_visible_month = dt(int(y), int(m), int(d)),
date = str(dtm.date.today()),
),
)),
html.Td([html.Label(‘Lot#/MotherLotNo’),
dcc.Input(id = ‘lot’, type = ‘text’,
placeholder = “ABC1234567”, value = ‘’,
maxLength = 1100)
]),
html.Td([html.Label(‘StationID/Chamber’),
dcc.Dropdown(
id = ‘station_id_dropdown’,
value = ,
multi = True)]),
html.Td([html.Label(‘SputterPOS’),
dcc.Dropdown(id = ‘sputterpos’,
options = [
{‘label’: ‘P1’, ‘value’: ‘P1’},
{‘label’: ‘P2’, ‘value’: ‘P2’}
],
value = ,
multi = True,
disabled = True)
]),
html.Tr(
[
html.Button(
id = ‘add_event_btn’,
children = ‘Submit’,
style = {
‘display’: ‘inline-block’,
‘verticalAlign’: ‘top’,
‘width’: ‘100%’
}

                               )
                           ]),

                   ])),
                   html.Div(children = html.Div(dcc.Loading(id = 'es-as-datatable'))),

                   ])

@app.callback(
Output(‘from_date’, ‘date’),
[Input(‘site’, ‘value’)]
)
def update(value):
if value in (‘GO’, ‘SZ’, ‘PN’):
return str(dtm.date.today())

@app.callback(
Output(‘to_date’, ‘date’),
[Input(‘site’, ‘value’)]
)
def update(value):
if value in (‘GO’, ‘SZ’, ‘PN’):
return str(dtm.date.today())

@app.callback(
Output(‘sputterpos’, ‘disabled’),
[Input(‘site’, ‘value’)]
)
def trigger_function(value):
if value == ‘PN’:
return False
else:
return True

@app.callback(
Output(‘station_id_dropdown’, ‘value’),
[Input(‘site’, ‘value’)])
def update(value):
if value == ‘GO’:
return ‘’
elif value == ‘SZ’:
return ‘’

@app.callback(
Output(‘lot’, ‘value’),
[Input(‘site’, ‘value’)])
def update(value):
if value == ‘GO’:
return ‘’
elif value == ‘SZ’:
return ‘’
elif value == ‘PN’:
return ‘’

@app.callback(
dash.dependencies.Output(‘machine_dropdown’, ‘options’),
[dash.dependencies.Input(‘site’, ‘value’)])
def set_cities_options(selected_machine):
return [{‘label’: i, ‘value’: i} for i in machine_options[selected_machine]]

@app.callback(
dash.dependencies.Output(‘station_id_dropdown’, ‘options’),
[dash.dependencies.Input(‘site’, ‘value’)])
def set_cities_options(selected_station_id):
return [{‘label’: i, ‘value’: i} for i in station_id_options[selected_station_id]]

@app.callback(
Output(‘es-as-datatable’, ‘children’),
[Input(‘add_event_btn’, ‘n_clicks’)],
[State(‘site’, ‘value’),
State(‘machine_dropdown’, ‘value’),
State(‘from_date’, ‘date’),
State(‘to_date’, ‘date’),
State(‘lot’, ‘value’),
State(‘station_id_dropdown’, ‘value’),
State(‘sputterpos’, ‘value’)]
)
def update_output_div(clicks, site, machine_dropdown, from_date, to_date, lot, station_id_dropdown, sputterpos):
global out_filename, merged_df
if clicks:
time.sleep(1)

out_data_table = html.Div([dst.DataTable(
data = merged_df.head(500).to_dict(‘rows’),
columns = [{‘name’: i, ‘id’: i} for i in merged_df.columns],
style_header = {‘backgroundColor’: “#FFD700”,
‘fontWeight’: ‘bold’,
‘textAlign’: ‘center’, },
style_table = {‘overflowX’: ‘scroll’},
style_cell = {‘minWidth’: ‘180px’, ‘width’: ‘180px’,
‘maxWidth’: ‘180px’, ‘whiteSpace’: ‘normal’},
filter_action = “native”,
sort_action = “native”,
sort_mode = “multi”,
column_selectable = “single”,
row_selectable = “multi”,
selected_columns = ,
selected_rows = ,
page_action = “native”,
page_current = 0,
page_size = 50,
), html.A(‘Download Zip’,
id = ‘download-zip’,
download = out_filename,
href = “”,
target = “_blank”,
n_clicks = 0)])
return out_data_table

@app.callback(
Output(‘download-zip’, ‘href’),
[Input(‘download-zip’, ‘n_clicks’)])
def generate_report_url(n_clicks):
return ‘/dash/urldownload’

@app.server.route(’/dash/urldownload’)
def generate_report_url():
compression_opts = dict(method = ‘zip’,
archive_name = out_filename + ‘.csv’)

# Create zip file in memory
merged_df.to_csv(out_filename + '.zip', compression = compression_opts, index = False)
return send_file(out_filename + '.zip', attachment_filename = out_filename + '.zip', as_attachment = True)

if name == ‘main’:

while True:
    object_es = WebElasticSearch()
    app.run_server(debug = True, host = "0.0.0.0", port = 8050)