-
Hi, I'm using wave as a frontend for my web api and started with the navbar+header template to get the app set up. I have some status data that I'd like to display to the user, for example, whether the background workers exposed by the api are available or not. Currently, I added a The two functions below take care of this, def get_worker_status():
header_worker_status_template = '<h3 style="color: {color};">Worker mode: {mode}</h3>'
success, mode = get_worker_mode() # wrapped http request to API
if success:
return header_worker_status_template.format(color="white", mode=_mode)
else:
return header_worker_status_template.format(color="red", mode="none")
def on_page(q: Q, page: str, ignore: Optional[List[str]] = []):
q.page['sidebar'].value = page
q.page['header'].items = [ui.markup(name="markup", content=get_worker_status())]
clear_cards(q, ignore) Next better implementation would be to run this status check in the background and broadcast it to all users and clients. I'm not sure if and how this is possible with wave. I read the docs on realtime sync but it's my impression that The only other option I'd considered is to use an inline script to update the markup card. But I wanted to mention the issue here in case there are better solutions or in case this might be an interesting general feature to add. |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 5 replies
-
Hey @aranvir.
Correct. This wouldn't be suitable for yourcase.
Hm.. not sure why inline script would be needed? You can update the header card directly from python (I am missing something probably). I suggest reading this blog post to see how this problem is usually solved in general. |
Beta Was this translation helpful? Give feedback.
-
QuestionHi @mturoci , I have a follow-up question since I'm running into some issues for my use case that are "probably" design mistakes on my side. Is there a way for the app to be notified when a client is closed? I see the BackgroundMy idea was: The heartbeat of my API sends its current mode as message. The status header shall display this mode or "none" when no heartbeat is received. This works in principle, BUT when I open a new tab (ergo, new client) the status bar is not updated anymore. Only the original client gets the live updates. All others just keep the value of I know that instead of globals I could also use The issue in either case is that the "refreshing future" is only started for the first visitor. I went for this solution because:
I tried to "hack" some broadcasting for this future but was unsuccessful. I assume the correct way to implement this feature would be to have one future per client but also requires "future clean-up" to not eventually have dozens of dead futures looping around. Code...
APP_INITIALIZED = False
API_STATUS = ""
async def update_worker_status(q: Q):
"""Update worker status if change occurred"""
global API_STATUS
logger.info("Starting worker status update...")
if "API_HEARTBEAT" in os.environ:
address = os.getenv("API_HEARTBEAT")
else:
address = "tcp://localhost:9000"
subscriber = basic_sockets.AsyncSubscriber(address) # convenience wrapper of a zmq SUB socket
subscriber.connect()
q.page['header'].items = [ui.markup(name="markup", content=_format_worker_status(API_STATUS))]
while True:
try:
value = await subscriber.recv_without_cb()
except Exception as e:
logger.error("Unhandled error experienced for update_worker_status", exc_info=e)
else:
if value != API_STATUS:
fmt_value = _format_worker_status(value)
q.page['header'].items = [ui.markup(name="markup", content=fmt_value)]
API_STATUS = value
await q.page.save()
...
async def init(q: Q) -> None:
...
q.page['header'] = ui.header_card(
box='header', title='', subtitle='',
secondary_items=[ui.textbox(name='search', icon='Search', width='400px', height='150px', placeholder='Search...')],
items=[
ui.markup(name="markup", content=_format_worker_status(API_STATUS))
]
)
...
@app('/')
async def serve(q: Q):
# Run only once per client connection.
global APP_INITIALIZED
if not q.client.initialized:
q.client.cards = set()
await init(q)
q.client.initialized = True
if not APP_INITIALIZED:
q.client.future = asyncio.ensure_future(update_worker_status(q))
APP_INITIALIZED = True
# Handle routing.
await handle_on(q)
await q.page.save() |
Beta Was this translation helpful? Give feedback.
Hey @aranvir.
Correct. This wouldn't be suitable for yourcase.
Hm.. not sure why inline script would be needed? You can update the header card directly from python (I am missing something probably).
I suggest reading this blog post to see how this problem is usually solved in general.