Skip to main content

Integrate Resonate into an existing project

How to integrate Resonate into an existing project.

You can integrate Resonate into an existing project by just adding the Resonate SDK as a dependency and initializing it in your Worker or Application Node. You don't need to run a Resonate Server to get started — Resonate will store all promises in local memory, until you are ready to add remote invocations and long term durability to your application.

Add the SDK to your project

Add the Resonate SDK to your project as a dependency.

uv add resonate-sdk

Initialize Resonate

Then, initialize Resonate in your script, worker, or application.

You can intialize Resonate in local memory, which does not require any additional dependencies (such as a Resonate Server). This is a great way to get started and test the integration.

When you are ready to add long term durability and remote invocations, you can switch to a remote store and message source (Resonate Server).

from resonate import Resonate

# Initialize Resonate with a local promise store
# Great for local development.
resonate = Resonate.local()

# Initialize Resonate with a remote promise store
# Great for building production grade distributed applications.
resonate = Resonate.remote()
Optional Remote mode

Make sure you run a Resonate Server prior to initializing Resonate with .remote()

brew install resonatehq/tap/resonate
resonate serve

If you don't have brew, see the Server installation guide for more installation options.

Register a function

Next, register a function with Resonate. Functions registered and invoked with Resonate gain durable qualities and can be awaited on remotely.

Register a function with Resonate using the register decorator or the register method.

All functions registered with Resonate or called from a Resonate function must define Context as the first argument.

# Register a function with the decorator
@resonate.register
def foo(ctx: Context, arg: str) -> str:
# Your function logic here
return result

# Register a function with the register method
def foo(ctx: Context, arg: str) -> str:
# Your function logic here
return result

resonate.register(foo)

# ...

resonate.start()

Calling resonate.start() explicitly starts Resonate instance threads. It is not needed in scripts, workers, or application nodes that call resonate.run(), but we recommend doing so with all instances of Resonate.

Invoke a function

You can invoke a function that is defined locally in the script, worker, or application node, or you can invoke a function that is defined remotely in a different worker or application . Invoking a function locally does not require the Resonate Server, but invoking one remotely does.

If the function is in the same Worker or Application Node, you can invoke it directly with the Resonate Client's Run API.

result = foo.run(promise_id, arg=arg)

# or using the Resonate Client
result = resonate.run(promise_id, func="foo", arg=arg)

If the function is in a different Worker or Application Node, you can invoke it with the rpc method on the Resonate instance. To do this, your worker must be connected to a remote store and message source (Resonate Server).

result = resonate
.options(target="<transport_plugin>://<unique_id>@<group>/<id>")
.rpc(promise_id, func="foo", arg=arg)

Extend the Call Graph

You can extend your Call Graph by invoking other functions from within a function.

@resonate.register
def foo(ctx: Context, arg: str) -> str:
# ...
r1 = yield ctx.run(bar, arg)
r2 = yield ctx.run(baz, r1)
return r2