Skip to content

Commit 7bd78a3

Browse files
feat!: add app.state (#80)
* refactor!: change AppState to StateSnapshot to better express it * feat!: add `app.state` Adds 2 new system tasks to load and store a snapshot of state. Currently this is just `last_block_processed` and `last_block_seen`. This paves the way for the `Parameter` feature, but does not include that just yet. BREAKING CHANGE: state snapshotting migrates from runner to worker * refactor: update from peer review * docs: add more color in docs for `app.state` Also updated docstrings within `silverback/application.py` * fix: don't raise error on exit, only note the error * refactor: have runner load and save the snapshot in datastore * docs: add a note to example about using worker startup event * docs: show off `app.state` and `CircuitBreaker` with more common example * docs: add another commit about triggering a txn to userguide * refactor(middlware): don't display INFO logs for system task start * feat!: change SilverbackApp to SilverbackBot and all changes surrounding it * fix: dockerfile * fix: bad isort * fix: docs surrounding app vs bot * fix: minor rewording in development docs * fix: add taskiq-redis * fix: typo --------- Co-authored-by: johnson2427 <blakeejohnson39@gmail.com>
1 parent e4925e3 commit 7bd78a3

File tree

14 files changed

+383
-184
lines changed

14 files changed

+383
-184
lines changed

Dockerfile

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,14 @@ RUN pip wheel . --wheel-dir=/wheels
1616
# Install from wheels
1717
FROM ghcr.io/apeworx/ape:${BASE_APE_IMAGE_TAG:-latest}
1818
USER root
19-
COPY --from=builder /wheels /wheels
19+
COPY --from=builder /wheels/*.whl /wheels
2020
RUN pip install --upgrade pip \
21-
&& pip install silverback \
21+
&& pip install \
22+
--no-cache-dir --find-links=/wheels \
2223
'taskiq-sqs>=0.0.11' \
23-
--no-cache-dir --find-links=/wheels
24+
'taskiq-redis>=1.0.2,<2' \
25+
silverback
26+
2427
USER harambe
2528

2629
ENTRYPOINT ["silverback"]

README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
# Quick Start
22

33
Silverback lets you create and deploy your own Python bots that respond to on-chain events.
4-
The Silverback library leverages the [Ape](https://docs.apeworx.io/ape/stable/userguides/quickstart) development framework as well as it's ecosystem of plugins and packages to enable you to develop simple-yet-sophisticated automated applications that can listen and respond to live chain data.
4+
The Silverback library leverages the [Ape](https://docs.apeworx.io/ape/stable/userguides/quickstart) development framework as well as it's ecosystem of plugins and packages to enable you to develop simple-yet-sophisticated automated bots that can listen and respond to live chain data.
55

6-
Silverback applications are excellent for use cases that involve continuously monitoring and responding to on-chain events, such as newly confirmed blocks or contract event logs.
6+
Silverback bots are excellent for use cases that involve continuously monitoring and responding to on-chain events, such as newly confirmed blocks or contract event logs.
77

8-
Some examples of these types of applications:
8+
Some examples of these types of bots:
99

1010
- Monitoring new pool creations, and depositing liquidity
1111
- Measuring trading activity of popular pools
1212
- Listening for large swaps to update a telegram group
1313

1414
## Documentation
1515

16-
Please read the [development userguide](https://docs.apeworx.io/silverback/stable/userguides/development.html) for more information on how to develop an application.
16+
Please read the [development userguide](https://docs.apeworx.io/silverback/stable/userguides/development.html) for more information on how to develop a bot.
1717

1818
## Dependencies
1919

@@ -72,11 +72,11 @@ Silverback will automatically register files in this folder as separate bots tha
7272

7373
```{note}
7474
It is also suggested that you treat this as a scripts folder, and do not include an __init__.py
75-
If you have a complicated project, follow the previous example to ensure you run the application correctly.
75+
If you have a complicated project, follow the previous example to ensure you run the bot correctly.
7676
```
7777

7878
```{note}
79-
A final suggestion would be to name your `SilverbackApp` object `bot`. Silverback automatically searches
79+
A final suggestion would be to name your `SilverbackBot` object `bot`. Silverback automatically searches
8080
for this object name when running. If you do not do so, once again, ensure you replace `example` with
8181
`example:<name-of-object>` the previous example.
8282
```
@@ -139,7 +139,7 @@ Traceback (most recent call last):
139139
ape_alchemy.exceptions.MissingProjectKeyError: Must set one of $WEB3_ALCHEMY_PROJECT_ID, $WEB3_ALCHEMY_API_KEY, $WEB3_ETHEREUM_MAINNET_ALCHEMY_PROJECT_ID, $WEB3_ETHEREUM_MAINNET_ALCHEMY_API_KEY.
140140
```
141141

142-
Go to [Alchemy](https://alchemy.com), create an account, then create an application in their dashboard, and copy the API Key.
142+
Go to [Alchemy](https://alchemy.com), create an account, then create an bot in their dashboard, and copy the API Key.
143143

144144
Another requirement for the command from `Docker Usage` to run the given example is that it uses [ape-tokens](https://github.com/ApeWorX/ape-tokens) plugin to look up token interfaces by symbol.
145145
In order for this to work, you should have installed and configured that plugin using a token list that includes both YFI and USDC on Ethereum mainnet.

docs/userguides/development.md

Lines changed: 66 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# Developing Applications
1+
# Developing Bots
22

3-
In this guide, we are going to show you more details on how to build an application with Silverback.
3+
In this guide, we are going to show you more details on how to build an bot with Silverback.
44

55
## Prerequisites
66

@@ -15,15 +15,15 @@ There are 3 suggested ways to structure your project. In the root directory of y
1515

1616
2. Create a `bots/` folder. Then develop bots in this folder as separate scripts (Do not include a __init__.py file).
1717

18-
3. Create a `bot/` folder with a `__init__.py` file that will include the instantiation of your `SilverbackApp()` object.
18+
3. Create a `bot/` folder with a `__init__.py` file that will include the instantiation of your `SilverbackBot()` object.
1919

2020
The `silverback` cli automatically searches for python scripts to run as bots in specific locations relative to the root of your project.
2121
It will also be able to detect the scripts inside your `bots/` directory and let you run those by name (in case you have multiple bots in your project).
2222

2323
If `silverback` finds a module named `bot` in the root directory of the project, then it will use that by default.
2424

2525
```{note}
26-
It is suggested that you create the instance of your `SilverbackApp()` object by naming the variable `bot`, since `silverback` will autodetect that variable name when loading your script file.
26+
It is suggested that you create the instance of your `SilverbackBot()` object by naming the variable `bot`, since `silverback` will autodetect that variable name when loading your script file.
2727
```
2828

2929
Another way you can structure your bot is to create a `bot` folder and define a runner inside of that folder as `__init__.py`.
@@ -43,7 +43,7 @@ If your bot's module name is `example.py` (for example), you can run it like thi
4343
silverback run example --network your:network:of:choice
4444
```
4545

46-
If the variable that you call the `SilverbackApp()` object is something other than `bot`, you can specific that by adding `:{variable-name}`:
46+
If the variable that you call the `SilverbackBot()` object is something other than `bot`, you can specific that by adding `:{variable-name}`:
4747

4848
```bash
4949
silverback run example:my_bot --network your:network:of:choice
@@ -52,7 +52,7 @@ silverback run example:my_bot --network your:network:of:choice
5252
We will automatically detect all scripts under the `bots/` folder automatically, but if your bot resides in a location other than `bots/` then you can use this to run it:
5353

5454
```bash
55-
silverback run folder.example:app --network your:network:of:choice
55+
silverback run folder.example:bot --network your:network:of:choice
5656
```
5757

5858
Note that with a `bot/__init__.py` setup, silverback will also autodetect it, and you can run it with:
@@ -69,21 +69,21 @@ For the most streamlined experience, develop your bots as scripts, and avoid rel
6969
If you follow these suggestions, your Silverback deployments will be easy to use and require almost no thought.
7070
```
7171

72-
## Creating an Application
72+
## Creating a Bot
7373

74-
Creating a Silverback Application is easy, to do so initialize the `silverback.SilverbackApp` class:
74+
Creating a Silverback Bot is easy, to do so initialize the `silverback.SilverbackBot` class:
7575

7676
```py
77-
from silverback import SilverbackApp
77+
from silverback import SilverbackBot
7878

79-
bot = SilverbackApp()
79+
bot = SilverbackBot()
8080
```
8181

82-
The SilverbackApp class handles state and configuration.
82+
The SilverbackBot class handles state and configuration.
8383
Through this class, we can hook up event handlers to be executed each time we encounter a new block or each time a specific event is emitted.
84-
Initializing the app creates a network connection using the Ape configuration of your local project, making it easy to add a Silverback bot to your project in order to perform automation of necessary on-chain interactions required.
84+
Initializing the bot creates a network connection using the Ape configuration of your local project, making it easy to add a Silverback bot to your project in order to perform automation of necessary on-chain interactions required.
8585

86-
However, by default an app has no configured event handlers, so it won't be very useful.
86+
However, by default an bot has no configured event handlers, so it won't be very useful.
8787
This is where adding event handlers is useful via the `bot.on_` method.
8888
This method lets us specify which event will trigger the execution of our handler as well as which handler to execute.
8989

@@ -161,9 +161,9 @@ def block_handler(block, context: Annotated[Context, TaskiqDepends()]):
161161
...
162162
```
163163

164-
### Application Events
164+
### Bot Events
165165

166-
You can also add an application startup and shutdown handler that will be **executed once upon every application startup**. This may be useful for things like processing historical events since the application was shutdown or other one-time actions to perform at startup.
166+
You can also add an bot startup and shutdown handler that will be **executed once upon every bot startup**. This may be useful for things like processing historical events since the bot was shutdown or other one-time actions to perform at startup.
167167

168168
```py
169169
@bot.on_startup()
@@ -180,7 +180,46 @@ def handle_on_shutdown():
180180
...
181181
```
182182

183-
*Changed in 0.2.0*: The behavior of the `@bot.on_startup()` decorator and handler signature have changed. It is now executed only once upon application startup and worker events have moved on `@bot.on_worker_startup()`.
183+
*Changed in 0.2.0*: The behavior of the `@bot.on_startup()` decorator and handler signature have changed. It is now executed only once upon bot startup and worker events have moved on `@bot.on_worker_startup()`.
184+
185+
## Bot State
186+
187+
Sometimes it is very useful to have access to values in a shared state across your workers.
188+
For example you might have a value or complex reference type that you wish to update during one of your tasks, and read during another.
189+
Silverback provides `bot.state` to help with these use cases.
190+
191+
For example, you might want to pre-populate a large dataframe into state on startup, keeping that dataframe in sync with the chain through event logs,
192+
and then use that data to determine a signal under which you want trigger transactions to commit back to the chain.
193+
Such an bot might look like this:
194+
195+
```py
196+
@bot.on_startup()
197+
def create_table(startup_state):
198+
df = contract.MyEvent.query(..., start_block=startup_state.last_block_processed)
199+
... # Do some further processing on df
200+
bot.state.table = df
201+
202+
203+
@bot.on_(contract.MyEvent)
204+
def update_table(log):
205+
bot.state.table = ... # Update using stuff from `log`
206+
207+
208+
@bot.on_(chain.blocks)
209+
def use_table(blk):
210+
if bot.state.table[...].mean() > bot.state.table[...].sum():
211+
# Trigger your bot to send a transaction from `bot.signer`
212+
contract.myMethod(..., sender=bot.signer)
213+
...
214+
```
215+
216+
```{warning}
217+
You can use `bot.state` to store any python variable type, however note that the item is not networked nor threadsafe so it is not recommended to have multiple tasks write to the same value in state at the same time.
218+
```
219+
220+
```{note}
221+
Bot startup and bot runtime event triggers (e.g. block or event container) are handled distinctly and can be trusted not to execute at the same time.
222+
```
184223

185224
### Signing Transactions
186225

@@ -192,10 +231,10 @@ While not recommended, you can use keyfile accounts for automated signing.
192231
See [this guide](https://docs.apeworx.io/ape/stable/userguides/accounts.html#automation) to learn more about how to do that.
193232
```
194233

195-
## Running your Application
234+
## Running your Bot
196235

197236
Once you have programmed your bot, it's really useful to be able to run it locally and validate that it does what you expect it to do.
198-
To run your bot locally, we have included a really useful cli command [`run`](../commands/run) that takes care of connecting to the proper network, configuring signers (using your local Ape accounts), and starting up the application client and in-memory task queue workers.
237+
To run your bot locally, we have included a really useful cli command [`run`](../commands/run) that takes care of connecting to the proper network, configuring signers (using your local Ape accounts), and starting up the bot client and in-memory task queue workers.
199238

200239
```sh
201240
# Run your bot on the Ethereum Sepolia testnet, with your own signer:
@@ -206,20 +245,20 @@ $ silverback run my_bot --network :sepolia --account acct-name
206245
`my_bot:bot` is not required for silverback run if you follow the suggested folder structure at the start of this page, you can just call it via `my_bot`.
207246
```
208247

209-
It's important to note that signers are optional, if not configured in the application then `bot.signer` will be `None`.
210-
You can use this in your application to enable a "test execution" mode, something like this:
248+
It's important to note that signers are optional, if not configured in the bot then `bot.signer` will be `None`.
249+
You can use this in your bot to enable a "test execution" mode, something like this:
211250

212251
```py
213252
# Compute some metric that might lead to creating a transaction
214253
if bot.signer:
215-
# Execute a transaction via `sender=app.signer`
254+
# Execute a transaction via `sender=bot.signer`
216255
else:
217256
# Log what the transaction *would* have done, had a signer been enabled
218257
```
219258

220259
```{warning}
221-
If you configure your application to use a signer, and that signer signs anything given to it, remember that you can lose substational amounts of funds if you deploy this to a production network.
222-
Always test your applications throughly before deploying, and always use a dedicated key for production signing with your application in a remote setting.
260+
If you configure your bot to use a signer, and that signer signs anything given to it, remember that you can lose substational amounts of funds if you deploy this to a production network.
261+
Always test your bots throughly before deploying, and always use a dedicated key for production signing with your bot in a remote setting.
223262
```
224263

225264
```{note}
@@ -230,7 +269,7 @@ Use segregated keys and limit your risk by controlling the amount of funds that
230269
### Distributed Execution
231270

232271
Using only the `silverback run ...` command in a default configuration executes everything in one process and the job queue is completely in-memory with a shared state.
233-
In some high volume environments, you may want to deploy your Silverback application in a distributed configuration using multiple processes to handle the messages at a higher rate.
272+
In some high volume environments, you may want to deploy your Silverback bot in a distributed configuration using multiple processes to handle the messages at a higher rate.
234273

235274
The primary components are the client and workers. The client handles Silverback events (blocks and contract event logs) and creates jobs for the workers to process in an asynchronous manner.
236275

@@ -265,10 +304,10 @@ silverback worker -w 2
265304

266305
The client will send tasks to the 2 worker subprocesses, and all task queue and results data will be go through Redis.
267306

268-
## Testing your Application
307+
## Testing your Bot
269308

270309
TODO: Add backtesting mode w/ `silverback test`
271310

272-
## Deploying your Application
311+
## Deploying your Bot
273312

274-
Check out the [Platform Deployment Userguide](./platform.html) for more information on how to deploy your application to the [Silverback Platform](https://silverback.apeworx.io).
313+
Check out the [Platform Deployment Userguide](./platform.html) for more information on how to deploy your bot to the [Silverback Platform](https://silverback.apeworx.io).

docs/userguides/platform.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
# Deploying Applications
1+
# Deploying Bots
22

33
In this guide, we are going to show you more details on how to deploy your application to the [Silverback Platform](https://silverback.apeworx.io).
44

55
## Creating a Cluster
66

7-
The Silverback Platform runs your Applications (or "Bots") on dedicated managed application Clusters.
7+
The Silverback Platform runs your Bots on dedicated managed application Clusters.
88
These Clusters will take care to orchestrate infrastructure, monitor, run your triggers, and collect metrics for your applications.
99
Each Cluster is bespoke for an individual or organization, and isolates your applications from others on different infrastructure.
1010

11-
Before we deploy our Application, we have to create a Cluster.
11+
Before we deploy our Bot, we have to create a Cluster.
1212
If you haven't yet, please sign up for Silverback at [https://silverback.apeworx.io](https://silverback.apeworx.io).
1313

1414
Once you have signed up, you can actually create (and pay for) your Clusters from the Silverback CLI utility by first
@@ -44,7 +44,7 @@ For instance, to list all your available bots on your cluster, use [`silverback
4444
To obtain general information about your cluster, just use [`silverback cluster info`][silverback-cluster-info],
4545
or [`silverback cluster health`][silverback-cluster-health] to see the current status of your Cluster.
4646

47-
If you have no bots, we will first have to containerize our Applications and upload them to a container registry that our Cluster is configured to access.
47+
If you have no bots, we will first have to containerize our Bots and upload them to a container registry that our Cluster is configured to access.
4848

4949
```{note}
5050
Building a container for your application can be an advanced topic, we have included the `silverback build` subcommand to help assist in generating Dockerfiles.
@@ -108,7 +108,7 @@ Silverback Clusters include an environment variable management system for exactl
108108
which you can manage using [`silverback cluster vars`][silverback-cluster-vars] subcommand.
109109

110110
The environment variable management system makes use of a concept called "Variable Groups" which are distinct collections of environment variables meant to be used together.
111-
These variable groups will help in managing the runtime environment of your Applications by allowing you to segregate different variables depending on each bot's needs.
111+
These variable groups will help in managing the runtime environment of your Bots by allowing you to segregate different variables depending on each bot's needs.
112112

113113
To create an environment group, use the [`silverback cluster vars new`][silverback-cluster-vars-new] command and give it a name and a set of related variables.
114114
For instance, it may make sense to make a group of variables for your favorite Ape plugins or services, such as RPC Providers, Blockchain Data Indexers, Etherscan, etc.
@@ -199,7 +199,7 @@ Any task execution that experiences an error will abort execution (and therefore
199199
All errors encountered during task exeuction are reported to the Cluster for later review by any users with appriopiate access.
200200
Tasks do not retry (by default), but updates to `app.state` are maintained up until the point an error occurs.
201201
202-
It is important to keep track of these errors and ensure that none of them are in fact critical to the operation of your Application,
202+
It is important to keep track of these errors and ensure that none of them are in fact critical to the operation of your Bot,
203203
and to take corrective or preventative action if it is determined that it should be treated as a more critical failure condition.
204204
```
205205

0 commit comments

Comments
 (0)