Server Module Problem: anvil.server.TimeoutError: Server code took too long

I am trying to make an app that predicts BTC stock. I created a server module with my code so I could use finance, but when I run it in my client code, an error message appears, reading “anvil.server.TimeoutError: Server code took too long”.

Server Module Code:
import anvil.google.auth, anvil.google.drive, anvil.google.mail
from anvil.google.drive import app_files
import anvil.server

@anvil.server.callable
def stockprediction():
import yfinance as yf
import math
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import pandas_datareader as web
import datetime as dt

from sklearn.preprocessing import MinMaxScaler
from keras.models import Sequential
from keras.layers import Dense, Dropout,LSTM
plt.style.use(‘fivethirtyeight’)

#Get today’s date
today = dt.date.today()
#Format the date as a string
today_str = today.strftime(‘%Y-%m-%d’)

#Get the stock quote

Use yfinance to download the data

df = yf.download(‘BTC-USD’, start=‘2012-01-01’, end=today_str)

#Get the number of rows and columns in the dataset
df.shape
#Create a new dataframe with only the close column
data = df.filter([‘Close’])
#Convert the dataframe to a numpy array
dataset = data.values
#Get the number of rows to train the model on
training_data_len = math.ceil( len(dataset) * .8 )

#Scale the data
scaler = MinMaxScaler(feature_range=(0,1))
scaled_data = scaler.fit_transform(dataset)

#Create the scaled training data set
train_data = scaled_data[0:training_data_len, :]
#Split the data into x_train and y_train data sets
x_train =
y_train =

for i in range(60, len(train_data)):
x_train.append(train_data[i-60:i, 0])
y_train.append(train_data[i, 0])

#Convert the x_train and y_train to numpy arrays
x_train, y_train = np.array(x_train), np.array(y_train)

#Reshape the data
x_train = np.reshape(x_train, (x_train.shape[0], x_train.shape[1], 1))

#Build the LSTM model
model = Sequential()
model.add(LSTM(50, return_sequences=True, input_shape= (x_train.shape[1], 1)))
model.add(LSTM(50, return_sequences= False))
model.add(Dense(25))
model.add(Dense(1))

#Compile the model
model.compile(optimizer=‘adam’, loss=‘mean_squared_error’)

#Train the model
model.fit(x_train, y_train, batch_size=1, epochs=1)

#Create the testing data set
test_data = scaled_data[training_data_len - 60: , :]
#Create the data set x_test and y_test
x_test =
for i in range(60, len(test_data)):
x_test.append(test_data[i-60:i,0])

#Convert the data to the numpy array
x_test = np.array(x_test)

#Reshape the data
x_test = np.reshape(x_test, (x_test.shape[0], x_test.shape[1], 1))

#Get the model’s predicted price values
predictions = model.predict(x_test)
predictions = scaler.inverse_transform(predictions)

#plot the data
valid = data[training_data_len:]
valid[‘Predictions’] = predictions

#Predict Next Day
#Assuming ‘data’ contains your entire dataset and ‘Close’ column is the target variable
model_inputs = data[len(data) - len(valid) - 60:].values
model_inputs = model_inputs.reshape(-1, 1)
model_inputs = scaler.transform(model_inputs)
real_data = [model_inputs[len(model_inputs) + 1 - 60:len(model_inputs+1), 0]]
real_data = np.array(real_data)
real_data = np.reshape(real_data, (real_data.shape[0], real_data.shape[1], 1))

prediction = model.predict(real_data)
prediction = scaler.inverse_transform(prediction)

prediction_text = str(prediction[0][0]) # Convert prediction to string

Create a figure and axes object

fig, ax = plt.subplots()

Display the prediction text with desired font size

ax.text(0.5, 0.5, prediction_text, fontsize=18, ha=‘center’, va=‘center’)

ax.axis(‘off’)

plt.show()
Client Code for the necessary page:
from ._anvil_designer import CurrentGraphTemplate
from anvil import *
import anvil.tables as tables
import anvil.tables.query as q
from anvil.tables import app_tables
import plotly.graph_objects as go
import anvil.server

class CurrentGraph(CurrentGraphTemplate):
def init(self, **properties):
# Set Form properties and Data Bindings.
self.init_components(**properties)

# Any code you write here will run before the form opens.

def currentgraph_button_click(self, **event_args):
anvil.server.call(‘stockprediction’)
What should I do to solve this (The code has no errors itself)?

That error isn’t because anything with your syntax is wrong, rather it’s just because your code takes too long to run on the server. There’s a 30 second time limit on server calls, but its longer for background tasks:

So I would either make the code more performant, switch to a background task, or switch to using anvil uplink:

1 Like

When I attempt to use background tasks, I get this problem, although I followed through with the necessary steps. Here is the server side code:
import anvil.google.auth, anvil.google.drive, anvil.google.mail
from anvil.google.drive import app_files
import anvil.server

Defining a Background Task

In a Server Module:

@anvil.server.background_task
def stockprediction():
import yfinance as yf
import math
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import pandas_datareader as web
import datetime as dt

from sklearn.preprocessing import MinMaxScaler
from keras.models import Sequential
from keras.layers import Dense, Dropout,LSTM
plt.style.use(‘fivethirtyeight’)

#Get today’s date
today = dt.date.today()
#Format the date as a string
today_str = today.strftime(‘%Y-%m-%d’)

#Get the stock quote

Use yfinance to download the data

df = yf.download(‘BTC-USD’, start=‘2012-01-01’, end=today_str)

#Get the number of rows and columns in the dataset
df.shape
#Create a new dataframe with only the close column
data = df.filter([‘Close’])
#Convert the dataframe to a numpy array
dataset = data.values
#Get the number of rows to train the model on
training_data_len = math.ceil( len(dataset) * .8 )

#Scale the data
scaler = MinMaxScaler(feature_range=(0,1))
scaled_data = scaler.fit_transform(dataset)

#Create the scaled training data set
train_data = scaled_data[0:training_data_len, :]
#Split the data into x_train and y_train data sets
x_train =
y_train =

for i in range(60, len(train_data)):
x_train.append(train_data[i-60:i, 0])
y_train.append(train_data[i, 0])

#Convert the x_train and y_train to numpy arrays
x_train, y_train = np.array(x_train), np.array(y_train)

#Reshape the data
x_train = np.reshape(x_train, (x_train.shape[0], x_train.shape[1], 1))

#Build the LSTM model
model = Sequential()
model.add(LSTM(50, return_sequences=True, input_shape= (x_train.shape[1], 1)))
model.add(LSTM(50, return_sequences= False))
model.add(Dense(25))
model.add(Dense(1))

#Compile the model
model.compile(optimizer=‘adam’, loss=‘mean_squared_error’)

#Train the model
model.fit(x_train, y_train, batch_size=1, epochs=1)

#Create the testing data set
test_data = scaled_data[training_data_len - 60: , :]
#Create the data set x_test and y_test
x_test =
for i in range(60, len(test_data)):
x_test.append(test_data[i-60:i,0])

#Convert the data to the numpy array
x_test = np.array(x_test)

#Reshape the data
x_test = np.reshape(x_test, (x_test.shape[0], x_test.shape[1], 1))

#Get the model’s predicted price values
predictions = model.predict(x_test)
predictions = scaler.inverse_transform(predictions)

#plot the data
valid = data[training_data_len:]
valid[‘Predictions’] = predictions

#Predict Next Day
#Assuming ‘data’ contains your entire dataset and ‘Close’ column is the target variable
model_inputs = data[len(data) - len(valid) - 60:].values
model_inputs = model_inputs.reshape(-1, 1)
model_inputs = scaler.transform(model_inputs)
real_data = [model_inputs[len(model_inputs) + 1 - 60:len(model_inputs+1), 0]]
real_data = np.array(real_data)
real_data = np.reshape(real_data, (real_data.shape[0], real_data.shape[1], 1))

prediction = model.predict(real_data)
prediction = scaler.inverse_transform(prediction)

prediction_text = str(prediction[0][0]) # Convert prediction to string

Create a figure and axes object

fig, ax = plt.subplots()

Display the prediction text with desired font size

ax.text(0.5, 0.5, prediction_text, fontsize=18, ha=‘center’, va=‘center’)

ax.axis(‘off’)

plt.show()
anvil.server.launch_background_task(‘stockprediction’)

Here is the client side code:
from ._anvil_designer import CurrentGraphTemplate
from anvil import *
import anvil.tables as tables
import anvil.tables.query as q
from anvil.tables import app_tables
import plotly.graph_objects as go
import anvil.server

class CurrentGraph(CurrentGraphTemplate):
def init(self, **properties):
# Set Form properties and Data Bindings.
self.init_components(**properties)

Any code you write here will run before the form opens.

def currentgraph_button_click(self, **event_args):
with anvil.server.no_loading_indicator:
self.task = anvil.server.call(‘stockprediction’)

Is there a problem with how I did this?

What error are you seeing? Also, please put your code between ``` like this example code. Also, to run a background_task, you need to use anvil.server.launch_background_task not anvil.server.call

Then you’ll want to change the way you receive the response like in this page:

Few issues I noticed

  1. You are calling a background function directly from client, not sure if that is supported , as indicated by @duncan_richards12 . Also, the client to server to client handoff/pattern does not look right.

  2. Once you fix the above issue, note that the server code is not returning anything. The plt.show is on the server side. You should return the figure object to the client, and make it the source for a client side plot component. Because it may take the background process a while to run, you may have to save the plot to a db record, and then pass it to the client by calling that record. Your client may have to pool the db record multiple times, until the background task finishes and write the plot (figure object) to that db record

I am seeing the error anvil.server.NoServerFunctionError: No server function matching “stockprediction” has been registered

Call a server function, and use that server function to launch your background task

1 Like

how exactly do you perform the second step

You might want to take a second look at

The very first snippet of code is just such an example.

I think you are still getting a hang of things. IMHO, do things stepwise

Iteration 1
write a client function to call a server function
Write a server function that returns a simple plot figure (should be fast)
On the client side, put the figure into a plot component

Iteration 2
write a client function to call a server function
Write a server function that launches a background task that runs and writes something to a db row (say a string that says "completed ")
On the client side, figure out a way to call this value from the db

Iteration 3
You have enough building blocks from 1 and 2 to complete your code

1 Like

My bad. I meant to say how do I return the figure object to the client without saying that a bunch of info is undefined. (The second problem with my code).

On the server side, for a plotly plot, it is simply

@anvil.server.callable
def your_plot_fn():
  #write your plotly code
  ...
  ...
  return Fig

(Note, this cannot be a background task, it has to be a server function)

On the client side, you have to assign this returned fig to a plot component

e.g.

Fig=anvil.server.call('your_plot_fn')
self.plot_1.figure=Fig

When I work on the server side, it says that many parts are undefined such as scaler or real_data. I defined them in my previous function but it loads as undefined. How do I fix this?

Does the function work in a Collab notebook? If so, maybe some Libraries are missing, e.g. Keras??

Please post errors that you are seeing, it’s hard to comment without the trace

The function does work in a Collab notebook. It is where I wrote the code originally. I defined everything needed in the background tasks within the same server module. Here is a file showing the undefined term. Looking at the previously pasted code, you can see that I did define prediction_text.

I did use @anvil.server.callable before the provided code

Not really. I see that the variable is defined, but I don’t see the scope. I don’t know if it’s defined in another module or in the same module, but during another call, or what else.

Keep in mind that every time something on the server side is executed, whether it is a form calling a server function, an http endpoint, a scheduled task, etc., a new Python interpreter is likely to start with no global variables defined.

2 Likes