reflex icon indicating copy to clipboard operation
reflex copied to clipboard

[Question] How to communicate frontend with a background thread?

Open FrankSFLYS opened this issue 3 months ago β€’ 1 comments

I am new to reflex. I'm developing an app that runs a background thread, polling and processing emails independently. After processing, data is stored into database. This app is meant to be single-end, so different frontend sessions can share same states. I want the frontend to reload whenever a new email is processed, or be notified by the polling thread.

There are two problems about this.

  1. Using app.register_lifespan_task(email_polling) works, but there are two instances running at the same time, and every cycle it runs, the reflex will be triggered to compile.
  2. How do I notify frontend to reload or fetch the newly added item whenever processed. The major question is how to communicate between background threads and frontend, and how to notify every frontend to reload. Because there are multiple items to show in a page, it will be better if I can only reload the ones that needed.

Thanks a lot!

Following is an MWE that shows how the first problem works:

"""Welcome to Reflex! This file outlines the steps to create a basic app."""
import asyncio

import reflex as rx

from rxconfig import config


class Item(rx.Model, table=True):
    name: str


async def polling_task():
    """This is the long-running polling task."""
    for i in range(100):
        with rx.session() as session:
            item = Item()
            item.name = str(i)
            session.add(item)
            session.commit()
            print(f'Task running - {item.name} added')
        await asyncio.sleep(5)


class State(rx.State):
    """The app state."""
    offset: int
    item: str

    @rx.event
    def load_items(self):
        with rx.session() as session:
            q = Item.select().offset(self.offset)
            item = session.exec(q).first()
            self.item = f'{self.offset} - {item.name}'
            self.offset += 1


def index() -> rx.Component:
    # Welcome Page (Index)
    return rx.container(
        rx.color_mode.button(position="top-right"),
        rx.vstack(
            rx.heading(
                State.item
            ),
            rx.button(
                "Load",
                on_click=State.load_items
            ),
            spacing="5",
            justify="center",
            min_height="85vh",
        ),
    )


app = rx.App()
app.register_lifespan_task(polling_task)
app.add_page(index)

And it runs:

Image

FrankSFLYS avatar Sep 04 '25 12:09 FrankSFLYS

why is it recompiling so much? when i run your example code on my local machine, i do not see the recompiles.

that said, in our upcoming release 0.8.18 there is a new feature that allows out of band updates to work in a general sense, and will be exposing an interface for enumerating connected clients in 0.8.19. so this server-triggered updates will be much nicer to deal with in future releases.

masenf avatar Oct 30 '25 22:10 masenf