2025, Oct 15 23:33
Taipy मल्टी‑पेज डैशबोर्ड में लाइव डेटा रिफ्रेश: ग्लोबल स्टेट, on_init और broadcast_callback
Taipy मल्टी‑पेज डैशबोर्ड में Postgres डेटा को ऑटो और ऑन‑डिमांड रिफ्रेश करें: ग्लोबल ऐप स्टेट, on_init व Gui.broadcast_callback से सभी सेशनों को अपडेट करें.
कई-पेज वाली Taipy ऐप में लाइव डेटा को रिफ्रेश करना सुनने में आसान लगता है, जब तक कि UI अपडेट होने से मना न कर दे। हेडर पेज, KPI ब्लॉक्स और अलग-अलग Analysis और Overview रूट्स वाली सामान्य सेटअप अक्सर एक बार लोड होकर जमी रह जाती है, जिससे “Refresh Now” बटन सत्रों में दिखने लायक कुछ नहीं करता। मकसद साफ है: Postgres से तय समय पर अपने-आप और बटन से ऑन-डिमांड नई पंक्तियाँ खींचना, और हर जुड़े उपयोगकर्ता को वही ताज़ा स्टेट दिखाना।
समस्या की रूपरेखा और न रिफ्रेश होने वाला पैटर्न
एप्लिकेशन KPIs और दो कंटेंट पेजों के लिए डेटा एक साझा मॉड्यूल से लोड करता है। नीचे दिया गया कोड वह पैटर्न दिखाता है जिसमें UI सभी उपयोगकर्ताओं और पेजों के लिए भरोसेमंद तरीके से रिफ्रेश नहीं होता।
# data/get_data.py
import psycopg2
import pandas as pd
from datetime import datetime, timedelta
PG_HOST = "localhost"
PG_PORT = "5432"
PG_DBNAME = "test"
PG_USER = "pg_db"
PG_PASSWORD = "Admin"
df_cache = None  # पेजों में साझा होने के लिए माना गया
day_slice = None
def pull_dataset():
    conn = psycopg2.connect(
        host=PG_HOST,
        port=PG_PORT,
        dbname=PG_DBNAME,
        user=PG_USER,
        password=PG_PASSWORD
    )
    query = "SELECT * FROM prod_db"
    df_cache = pd.read_sql(query, conn)
    df_cache['date'] = pd.to_datetime(df_cache['date'])
    df_cache.columns = ['Date', 'Location', 'Tower Name', 'Zone', 'Stage Label', 'Class Stage Label']
    yesterday = (datetime.now() - timedelta(days=1)).date()
    day_slice = df_cache[df_cache['Date'].dt.date == yesterday]
    day_slice = day_slice.sort_values(by='Class Stage Label', ascending=False)
    conn.close()
    return df_cache, day_slice
def refresh_store(state=None):
    global df_cache, day_slice
    df_cache, day_slice = pull_dataset()
    if state:
        state.df_cache = df_cache
        state.day_slice = day_slice
# main.py
from taipy.gui import Gui
import threading
import time
from data.get_data import refresh_store
from pages import root
from Analysis import analysis
from Overview import overview
# बैकग्राउंड लूप
def tick_loop(state):
    while True:
        time.sleep(300)
        refresh_store(state)
# GUI init पर शुरू करने की कोशिश
def boot_refresh(state):
    refresh_store(state)
    threading.Thread(target=tick_loop, args=(state,), daemon=True).start()
routes = {
    "/": home_view,
    "Analysis": analysis_view,
    "Overview": overview_view
}
Gui(pages=routes).run(on_init=boot_refresh)
# pages/root.py
from data.get_data import day_slice, refresh_store
import taipy.gui.builder as tgb
with tgb.Page() as home_view:
    tgb.text('## Performance Insights', mode='md')
    tgb.button('Refresh Now', on_action=refresh_store)
    with tgb.layout("1 1 1 1 1 1"):
        with tgb.part():
            tgb.text('### Date', mode='md')
            tgb.text("#### {','.join(day_slice['Date'].dt.strftime('%Y-%m-%d').unique())}", mode='md')
        with tgb.part():
            tgb.text('### Total', mode='md')
            tgb.text("#### {int(day_slice['Class Stage Label'].count())}", mode='md')
        with tgb.part():
            tgb.text('### Normal Stage', mode='md')
            tgb.text("#### {int(day_slice[day_slice['Class Stage Label']=='Normal'].shape[0])}", mode='md')
        with tgb.part():
            tgb.text('### Stage One', mode='md')
            tgb.text("#### {int(day_slice[day_slice['Class Stage Label']=='Stage1'].shape[0])}", mode='md')
        with tgb.part():
            tgb.text('### Stage Two', mode='md')
            tgb.text("#### {int(day_slice[day_slice['Class Stage Label']=='Stage2'].shape[0])}", class_name="lblink", mode='md')
        with tgb.part():
            tgb.text('### Stage Three', mode='md')
            tgb.text("#### {int(day_slice[day_slice['Class Stage Label']=='Stage3'].shape[0])}", class_name="blink", mode='md')
    tgb.navbar()
    with tgb.expandable(title='Data', expanded=False):
        tgb.table("{day_slice}")
असल में गड़बड़ी कहाँ होती है
डेटा ऑब्जेक्ट्स लोड भी होते हैं और दोबारा असाइन भी, लेकिन वे वहाँ नहीं रखे जाते जहाँ Taipy साझा एप्लिकेशन स्टेट की उम्मीद करता है। जिस मुख्य मॉड्यूल में Gui बनाया जाता है, उसके बाहर होने पर उन्हें सभी पेजों के बीच साझा ग्लोबल स्टेट नहीं माना जाता। रिफ्रेश लूप भी एक ही सेशन कॉन्टेक्स्ट को अपडेट करता है, बदलाव प्रसारित नहीं करता। अंत में, Gui.run में on_init कॉलबैक पास करने की कोशिश पकड़ में नहीं आती, क्योंकि यह पैरामीटर समर्थित नहीं है; Taipy मुख्य मॉड्यूल में on_init नाम का फ़ंक्शन खोजता है या gui.on_init के जरिए असाइनमेंट स्वीकार करता है।
समाधान: स्टेट को ऐप-स्तर पर ग्लोबल करें और रिफ्रेश को प्रसारित करें
सही तरीका यह है कि साझा वेरिएबल्स को मुख्य मॉड्यूल में इम्पोर्ट किया जाए ताकि Taipy उन्हें ऐप-स्तर के ग्लोबल स्टेट के रूप में माने, on_init के जरिए सेशन कनेक्ट होने पर उन्हें इनिशियलाइज़ किया जाए, और निर्धारित समय पर हर जुड़े उपयोगकर्ता तक अपडेट पहुँचाने के लिए broadcast_callback का उपयोग किया जाए। बटन उसी डेटा रिफ्रेश फ़ंक्शन से जुड़ा रहता है।
# main.py
from taipy.gui import Gui
import threading
import time
from data.get_data import refresh_store, df_cache, day_slice
from pages import root
from Analysis import analysis
from Overview import overview
# नया सेशन जुड़ते ही डेटा इनिशियलाइज़ करें
def on_init(state):
    refresh_store(state)
# सभी सेशनों तक नियमित रूप से रिफ्रेश प्रसारित करें
def auto_refresher(gui: Gui):
    while True:
        time.sleep(300)
        gui.broadcast_callback(refresh_store)
routes = {
    "/": home_view,
    "Analysis": analysis_view,
    "Overview": overview_view
}
gui = Gui(pages=routes)
thread = threading.Thread(target=auto_refresher, args=(gui,))
thread.start()
gui.run()
यह ढांचा तीन अहम काम करता है। पहला, df_cache और day_slice मुख्य मॉड्यूल के स्कोप में रहते हैं, इसलिए सभी पेज एक ही ऑब्जेक्ट्स साझा करते हैं। दूसरा, on_init हर नए सेशन पर चलता है और तुरंत state भर देता है। तीसरा, बैकग्राउंड थ्रेड किसी एक सेशन को नहीं छूता; यह broadcast_callback का उपयोग करके हर किसी के लिए एक साथ पाँच-मिनट के अंतराल पर रिफ्रेश फ़ंक्शन चलाता है।
Taipy डैशबोर्ड्स के लिए यह क्यों महत्वपूर्ण है
ऐसे डैशबोर्ड जो कई पन्नों में समेकित डेटा दिखाते हैं, उन्हें उपयोगकर्ता सत्रों में सुसंगत रहना चाहिए। साझा स्टेट को मुख्य मॉड्यूल में केंद्रीकृत करना और अपडेट प्रसारित करना सुनिश्चित करता है कि “Refresh Now” पर मैनुअल क्लिक और शेड्यूल्ड रिफ्रेश एक ही ऐप-वाइड परिणाम पर मिलें। यह प्रति-उपयोगकर्ता अलग-अलग स्टेट बनने से रोकता है और ऐसे शांत नो-ऑप रिफ्रेश से बचाता है जो UI अपडेट ही नहीं कराते।
समापन और व्यावहारिक सलाह
Gui के साथ मुख्य मॉड्यूल में ही साझा डेटा स्ट्रक्चर्स रखें ताकि वे Taipy का ग्लोबल स्टेट बन जाएँ। प्रत्येक सत्र को on_init फ़ंक्शन देकर इनिशियलाइज़ करें और Taipy को उसे स्वतः खोजने दें। सभी जुड़े उपयोगकर्ताओं तक आवधिक रिफ्रेश भेजने के लिए Gui.broadcast_callback का उपयोग करें। इस वायरिंग के साथ, आपके KPI और टेबल्स मांग पर और शेड्यूल दोनों में, हर पेज और हर सेशन में भरोसेमंद तरीके से अपडेट होते हैं।
यह लेख StackOverflow पर प्रश्न (लेखक: user3219244) और Zaccheus Sia के उत्तर पर आधारित है।