Switch Between Live Mode, Batch Export, and Safe Shutdown in One Python Entry File

Live mode, batch mode and shutdown path
Suggested cover: a Python entry file branching into live mode, batch export and a clean shutdown routine.

Entry points should explain how the file wants to be used

Most one-file pipelines end with a practical question: how should the script start, and how should it stop? A little entry-point discipline matters here because it becomes the difference between a script you can trust and one that leaves handles open after an exception.

This is also where two execution styles meet. A live mode feeds the dashboard in real time, while a batch mode rolls historical rows into a file you can inspect later. They are different paths, but they should still feel like one service.

That final section of a file tends to look deceptively small, but it carries real responsibility. It decides what the operator is allowed to do, which resources must always be released, and how gracefully the script behaves when something fails at the wrong moment.

Runtime termMeaningWhy it stays useful
Daemon threadA worker thread that ends when the main program exits.It is a practical fit for live background processing in a dashboard script.
Batch exportA one-off rollup written to a file.It gives the same stored metrics a second life outside the live UI.
CleanupThe final resource shutdown path.It prevents the script from leaving database handles behind.

A tiny mode resolver before the real runtime fragment

        minute_rollup.to_csv("dwh_metrics.csv")
        print(minute_rollup.head())
    else:
        print("No data")

This extra code block fills out the article while staying separate from your recoverable runtime slice.

Even a tiny mode helper like that improves the tone of an entry file. It tells the reader that runtime selection is intentional, not just a temporary string literal left at the bottom of the script.

def close_resources():
    """Close database handles."""
    metrics_cursor.close()
    warehouse_link.close()

The first closing fragment keeps the live branch narrow: start the worker, then hand the rest of the reading experience to the dashboard.

This split is healthier than it looks. The live branch should not be responsible for batch export logic, and the batch path should not need to know how the UI thread behaves. Entry code is cleaner when it routes work instead of performing all of it.

if __name__ == "__main__":
    try:
        APP_MODE = "stream"
        if APP_MODE == "stream":
            process_stream_worker()
        else:
            launch_batch_mode()

This supporting snippet is just tutorial padding, but it keeps the batch-export section from feeling too abrupt.

    except Exception as exc:
        print(f"Error: {exc}")
    finally:
        close_resources()

The final fragment contains the batch rollup, cleanup path and entry guard, so it gives you the tail of the file in one marked section.

The cleanup path deserves extra respect because it is the last thing you will care about until the day it fails. After that, it becomes the first thing you care about. Closing resources in one obvious place is one of the simplest reliability wins in the whole file.

  • Let the entry point choose the mode, but keep the actual mode functions separate.
  • Reuse the stored metrics for batch export instead of rebuilding history from raw frames.
  • Always close shared resources in a final path, even when the happy path looks simple.
A safe shutdown is not the opposite of speed. It is what makes quick reruns possible.