File size: 7,019 Bytes
036b3a6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
# Background Tasks


<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

Useful for operations where the user gets a response quickly but doesn’t
need to wait for the operation to finish. Typical scenarios include:

- User setup in complex systems where you can inform the user and other
  people later in email that their account is complete
- Batch processes that can take a significant amount of time (bulk email
  or API calls)
- Any other process where the user can be notified later by email,
  websocket, webhook, or pop-up

<div>

> **Note**
>
> Background tasks in FastHTML are built on Starlette’s background
> tasks, with added sugar. Starlette’s background task design is an
> easy-to-use wrapper around Python’s async and threading libraries.
> Background tasks make apps snappier to the end user and generally
> improve an app’s speed.

</div>

## A simple background task example

In this example we are attaching a task to FtResponse by assigning it
via the background argument. When the page is visited, it will display
‘Simple Background Task Example’ almost instantly, while in the terminal
it will slowly count upward from 0.

<div class="code-with-filename">

**main.py**

``` python
from fasthtml.common import *
from starlette.background import BackgroundTask
from time import sleep

app, rt = fast_app()

def counter(loops:int):
    "Slowly print integers to the terminal"
    for i in range(loops):
        print(i)
        sleep(i)

@rt
def index():
    task = BackgroundTask(counter, loops=5)
    return Titled('Simple Background Task Example'), task

serve()
```

</div>

Line 7  
`counter` is our task function. There is nothing special about it,
although it is a good practice for its arguments to be serializable as
JSON

Line 15  
We use `starlette.background.BackgroundTask` to turn `counter()` into a
background task

Line 16  
To add a background task to a handler, we add it to the return values at
the top level of the response.

## A more realistic example

Let’s imagine that we are accessing a slow-to-process critical service.
We don’t want our users to have to wait. While we could set up SSE to
notify on completion, instead we decide to periodically check to see if
the status of their record has changed.

### Simulated Slow API Service

First, create a very simple slow timestamp API. All it does is stall
requests for a few seconds before returning JSON containing timestamps.

``` python
# slow_api.py
from fasthtml.common import *
from time import sleep, time

app, rt = fast_app()

@rt('/slow')
def slow(ts: int):
    sleep(3)
    return dict(request_time=ts, response_time=int(time()))

serve(port=8123)
```

Line 9  
This represents slow processing.

Line 10  
Returns both the task’s original timestamp and the time after completion

### Main FastHTML app

Now let’s create a user-facing app that uses this API to fetch the
timestamp from the glacially slow service.

``` python
# main.py
from fasthtml.common import *
from starlette.background import BackgroundTask
import time
import httpx

app, rt = fast_app()

db = database(':memory:')

class TStamp: request_time: int; response_time: int

tstamps = db.create(TStamp, pk='request_time')

def task_submit(request_time: int):
    client = httpx.Client()
    response = client.post(f'http://127.0.0.1:8123/slow?ts={request_time}')
    tstamps.insert(**response.json())

@rt
def submit():
    "Route that initiates a background task and returns immediately."
    request_time = int(time.time())
    task = BackgroundTask(task_submit, request_time=request_time)
    return P(f'Request submitted at: {request_time}'), task

@rt
def show_tstamps(): return Ul(map(Li, tstamps()))

@rt
def index():
    return Titled('Background Task Dashboard',
        P(Button('Press to call slow service',
            hx_post=submit, hx_target='#res')),
        H2('Responses from Tasks'),
        P('', id='res'),
        Div(Ul(map(Li, tstamps())),
            hx_get=show_tstamps, hx_trigger='every 5s'),
    )

serve()
```

Line 11  
Tracks when requests are sent and responses received

Line 15  
Task function calling slow service to be run in the background of a
route handler. It is common but not necessary to prefix task functions
with ‘task\_’

Line 17  
Call the slow API service (simulating a time-consuming operation)

Line 18  
Store both timestamps in our database

Line 24  
Create a background task by passing in the function to a BackgroundTask
object, followed by any arguments.

Line 25  
In FtResponse, use the background keyword argument to set the task to be
run after the HTTP response is generated.

Line 28  
Endpoint that displays all recorded timestamp pairs.

Line 33  
When this button is pressed, the ‘submit’ handler will respond
instantly. The task_submit function will insert the slow API response
into the db later.

Line 38  
Every 5 seconds get the tstamps stored in the DB.

<div>

> **Tip**
>
> In the example above we use a synchronous background task function set
> in the
> [`FtResponse`](https://www.fastht.ml/docs/api/core.html#ftresponse) of
> a synchronous handler. However, we can also use asynchronous functions
> and handlers.

</div>

## Multiple background tasks in a handler

It is possible to add multiple background tasks to an FtResponse.

<div>

> **Warning**
>
> Multiple background tasks on a background task are executed in order.
> In the case a task raises an exception, following tasks will not get
> the opportunity to be executed.

</div>

``` python
from starlette.background import BackgroundTasks

@rt
async def signup(email, username):
    tasks = BackgroundTasks()
    tasks.add_task(send_welcome_email, to_address=email)
    tasks.add_task(send_admin_notification, username=username)
    return Titled('Signup successful!'), tasks

async def send_welcome_email(to_address):
    ...

async def send_admin_notification(username):
    ...
```

## Background tasks at scale

Background tasks enhance application performance both for users and apps
by handling blocking processes asynchronously, even when defined as
synchronous functions.

When FastHTML’s background tasks aren’t enough and your app runs slow on
a server, manually offloading processes to the `multiprocessing` library
is an option. By doing so you can leverage multiple cores and bypass the
GIL, significantly improving speed and performance at the cost of added
complexity.

Sometimes a server reaches its processing limits, and this is where
distributed task queue systems like Celery and Dramatiq come into play.
They are designed to distribute tasks across multiple servers, offering
improved observability, retry mechanisms, and persistence, at the cost
of substantially increased complexity.

However most applications work well with built-in background tasks like
those in FastHTML, which we recommend trying first. Writing these
functions with JSON-serializable arguments ensures straightforward
conversion to other concurrency methods if needed.