-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: manojdbos <[email protected]> Co-authored-by: Peter Kraft <[email protected]>
- Loading branch information
1 parent
9668a04
commit e34b046
Showing
18 changed files
with
422 additions
and
160 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
--- | ||
sidebar_position: 2 | ||
title: Operon Command line interface (CLI) | ||
--- | ||
|
||
The operon runtime with the application is started using the command line | ||
|
||
``` | ||
npx operon start -p <port> -l <loglevel> | ||
``` | ||
|
||
-p or --port: The http port on which the runtime with listen for http requests | ||
|
||
-l or --loglevel: 'info','warn','error','debug' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
--- | ||
sidebar_position: 1 | ||
title: Operon Configuration | ||
--- | ||
|
||
Configuration is set of properties and values provided by the application develop to influence the behaviour of the operon runtime as well as the application. | ||
|
||
## configuration file | ||
|
||
Standard yaml file operon-config.yaml. | ||
The file should be in the root directory of the project. | ||
A sample operon-config.yaml is shown below. | ||
|
||
A value in the form ${SOMEVALUE} implies that the runtime will get the value from the environment variable SOMEVALUE. | ||
|
||
``` | ||
database: | ||
hostname: 'localhost' | ||
port: 5432 | ||
username: 'postgres' | ||
password: ${PGPASSWORD} | ||
user_database: 'hello' | ||
system_database: 'hello_systemdb' | ||
connectionTimeoutMillis: 3000 | ||
user_dbclient: 'knex' | ||
telemetryExporters: | ||
- 'ConsoleExporter' | ||
``` | ||
|
||
## Operon configuration | ||
|
||
### database | ||
The database section contains configuration parameters needed by operon to connect to user and system databases. | ||
|
||
#### hostname | ||
The hostname or ip address of the machine hosting the database. | ||
|
||
#### port | ||
The port that the database is listening on. | ||
|
||
#### username | ||
The username to use to connect to the database. | ||
|
||
#### password | ||
The password to use to connect to the database. It is strongly recommended that you do not put password in cleartext here. Instead use indirection like ${PGPASSWORD} so that the runtime can get the value from the environment variable PGPASSWORD. | ||
|
||
#### user_database | ||
This is the database that the application code reads and writes from. | ||
|
||
#### system_database | ||
This is the database that the operon runtime reads and writes from. | ||
|
||
#### user_dbclient | ||
This is the sql builder or ORM used to communicate with the database. Supported values are knex, prisma or typeorm. Default is knex | ||
|
||
#### connectionTimeoutMillis | ||
The timeout in milliseconds after which the database driver will timeout from connecting to the database. | ||
|
||
#### observability_database | ||
The name of the database to which the observability database is written to. | ||
|
||
#### ssl_ca | ||
The path to ssl certificate to connect to the database. | ||
|
||
### localRuntimeConfig | ||
``` | ||
localRuntimeConfig | ||
port: 6000 | ||
``` | ||
This section has properties needed to configure the runtime. | ||
|
||
#### port | ||
This is the port on which the embedded http server listens. Default is 3000. | ||
|
||
|
||
### telemetryExporters | ||
|
||
List of exporter to whom telemetry logs are to be sent. Supported values are 'ConsoleExporter', 'JaegerExporter', 'PGExporter'. | ||
|
||
|
||
## Application configuration | ||
|
||
The application section can have any user defined properties and values used by the application. | ||
|
||
``` | ||
application: | ||
PAYMENTS_SERVICE: 'http://stripe.com/payment' | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
--- | ||
sidebar_position: 1 | ||
sidebar_position: 4 | ||
title: Operon Contexts | ||
--- | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"label": "Concepts and Explanations", | ||
"position": 4, | ||
"link": { | ||
"type": "generated-index", | ||
"description": "These explanations help you learn core Operon concepts." | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
--- | ||
sidebar_position: 1 | ||
title: Application Structure | ||
description: Learn about the structure of an Operon application | ||
--- | ||
|
||
In this guide, you'll learn about the structure of an Operon application. | ||
|
||
### Directory Structure | ||
|
||
When you initialize an Operon project with `npx operon init`, it has the following structure: | ||
|
||
```bash | ||
operon-hello-app/ | ||
├── README.md | ||
├── knexfile.ts | ||
├── migrations/ | ||
├── node_modules/ | ||
├── operon-config.yaml | ||
├── package-lock.json | ||
├── package.json | ||
├── src/ | ||
│ └── userFunctions.ts | ||
├── start_postgres_docker.sh | ||
└── tsconfig.json | ||
``` | ||
|
||
The two most important files in an Operon project are `operon-config.yaml` and `src/userFunctions.ts`. | ||
|
||
`operon-config.yaml` defines the configuration of an Operon project, including database connection information, ORM configuration, and global logging configuration. | ||
All options are documented in our [configuration reference](..). | ||
|
||
`src/userFunctions.ts` is where Operon looks for your code. | ||
At startup, the Operon runtime automatically loads all classes exported from this file, serving their endpoints and registering their transactions and workflows. | ||
If you're writing a small application, you can write all your code directly in this file. | ||
In a larger application, you can write your code wherever you want, but should use `src/userFunctions.ts` as an index file, exporting code written elsewhere. | ||
|
||
As for the rest of the directory: | ||
|
||
- `knexfile.ts` is a configuration file for [Knex](https://knexjs.org), which we use as a query builder and migration tool. | ||
- `migrations` is initialized with a Knex database migration used in the [quickstart guide](../getting-started/quickstart). If you're using Knex for schema management, you can create your own migrations here. | ||
- `node_modules`, `package-lock.json`, `package.json`, and `tsconfig.json` are needed by all Node/Typescript projects. | ||
- `start_postgres_docker.sh` is a convenience script that initializes a Docker-hosted Postgres database for use in the [quickstart](../getting-started/quickstart). You can modify this script if you want to use Docker-hosted Postgres for local development. | ||
|
||
### Code Structure | ||
|
||
Here's the initial source code generated by `npx operon init` (in `src/userFunctions.ts`): | ||
|
||
```javascript | ||
import { TransactionContext, OperonTransaction, GetApi, HandlerContext } from '@dbos-inc/operon' | ||
import { Knex } from 'knex'; | ||
|
||
type KnexTransactionContext = TransactionContext<Knex>; | ||
|
||
interface operon_hello { | ||
name: string; | ||
greet_count: number; | ||
} | ||
|
||
export class Hello { | ||
|
||
@OperonTransaction() | ||
static async helloTransaction(txnCtxt: KnexTransactionContext, name: string) { | ||
// Look up greet_count. | ||
let greet_count = await txnCtxt.client<operon_hello>("operon_hello") | ||
.select("greet_count") | ||
.where({ name: name }) | ||
.first() | ||
.then(row => row?.greet_count); | ||
if (greet_count) { | ||
// If greet_count is set, increment it. | ||
greet_count++; | ||
await txnCtxt.client<operon_hello>("operon_hello") | ||
.where({ name: name }) | ||
.increment('greet_count', 1); | ||
} else { | ||
// If greet_count is not set, set it to 1. | ||
greet_count = 1; | ||
await txnCtxt.client<operon_hello>("operon_hello") | ||
.insert({ name: name, greet_count: 1 }) | ||
} | ||
return `Hello, ${name}! You have been greeted ${greet_count} times.\n`; | ||
} | ||
|
||
@GetApi('/greeting/:name') | ||
static async helloHandler(handlerCtxt: HandlerContext, name: string) { | ||
return handlerCtxt.invoke(Hello).helloTransaction(name); | ||
} | ||
} | ||
|
||
``` | ||
An Operon application like this one is made up of classes encapsulating _functions_, written as decorated static class methods. | ||
There are four basic types of functions. | ||
This example contains two of them: | ||
- [**Transactions**](../tutorials/transaction-tutorial), like `helloTransaction` perform database operations. | ||
- [**Handlers**](../tutorials/http-serving-tutorial), like `helloHandler`, serve HTTP requests. | ||
There are two more: | ||
- [**Communicators**](../tutorials/communicator-tutorial) manage communication with external services and APIs. | ||
- [**Workflows**](../tutorials/workflow-tutorial) reliably orchestrate other functions. | ||
A function needs to follow a few rules: | ||
- It must be a static class method. For Operon to find it, that class must be exported from `src/userFunctions.ts`. | ||
- It must have a decorator telling Operon what kind of function it is: [`@OperonTransaction`](../api-reference/decorators#operontransaction) for transactions, [`@OperonCommunicator`](../api-reference/decorators#operoncommunicator) for communicators, [`@OperonWorkflow`](../api-reference/decorators#operonworkflow) for workflows, or [`GetApi`](../api-reference/decorators#getapi) or [`PostApi`](../api-reference/decorators#postapi) for handlers. | ||
- Its first argument must be the appropriate kind of [Operon context](../api-reference/contexts). Contexts provide functions with useful methods, such as access to a database client for transactions. | ||
- Its input and return types must be serializable to JSON. | ||
Once you've written your functions, there are two basic ways to call them: | ||
1. Any function (not just handlers) can be called from HTTP if it's annotated with the [`GetApi`](../api-reference/decorators#getapi) or [`PostApi`](../api-reference/decorators#postapi) decorators. See our [HTTP serving tutorial](../tutorials/http-serving-tutorial.md) for details. | ||
2. Handlers and workflows can invoke other functions via their contexts' [invoke](..) method. | ||
To learn more about each individual type of function and what it can do, see our [tutorials](../category/tutorials/). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
--- | ||
sidebar_position: 3 | ||
title: Communicators | ||
description: Learn how to communicate with external APIs and services | ||
--- | ||
|
||
In this guide, you'll learn how to communicate with external APIs and services from an Operon application. | ||
|
||
We recommend that all communication with external services be done in _communicator_ functions. | ||
For example, you can use communicators to serve a file from [AWS S3](https://aws.amazon.com/s3/), call an external API like [Stripe](https://stripe.com/) or access a non-Postgres data store like [Elasticsearch](https://www.elastic.co/elasticsearch/). | ||
Encapsulating these calls in communicators is especially important if you're using [workflows](..) as it lets the workflow know to make their results persistent through server failures. | ||
|
||
Communicators must be annotated with the [`@OperonCommunicator`](../api-reference/decorators#operoncommunicator) decorator and must have a [`CommunicatorContext`](..) as their first argument. | ||
Like for other Operon functions, inputs and outputs must be serializable to JSON. | ||
Here's a simple example using [Axios](https://axios-http.com/docs/intro) to call the [Postman Echo API](https://learning.postman.com/docs/developer/echo-api/): | ||
|
||
|
||
```javascript | ||
@OperonCommunicator() | ||
static async postmanEcho(_ctxt: CommunicatorContext) { | ||
const resp = await axios.get("https://postman-echo.com/get"); | ||
return resp.data; | ||
} | ||
``` | ||
|
||
### Retries | ||
|
||
By default, Operon automatically retries any communicator function that throws an exception. | ||
It retries communicator functions a set number of times with exponential backoff, throwing an [`OperonError`](..) if the maximum number of retries is exceed. | ||
Retries are fully configurable through arguments to the [`@OperonCommunicator`](../api-reference/decorators#operoncommunicator) decorator. |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.