-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #409 from wuespace/TELESTION-465
TELESTION-465: Deno samples
- Loading branch information
Showing
15 changed files
with
392 additions
and
0 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,3 @@ | ||
# Common sample service environment variables | ||
NATS_URL=nats:4222 | ||
DATA_DIR=/data |
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,57 @@ | ||
# Deno Backend Service Samples | ||
|
||
This directory contains samples for Deno backend service. | ||
|
||
## Adding a new sample | ||
|
||
To add a new sample, create a new directory under this directory. The directory | ||
name should be the name of the sample. For example, if you want to create a | ||
sample named `hello_world`, create a directory named `hello_world`. | ||
|
||
Inside the directory, create a `README.md` file that describes the sample. | ||
|
||
Most samples should also have a `mod.ts` file that contains the sample code. | ||
|
||
### Importing the Telestion Library | ||
|
||
To import the Telestion library, use the following import statement: | ||
|
||
```typescript | ||
import { startService } from "https://deno.land/x/telestion/mod.ts"; | ||
``` | ||
|
||
This ensures that the import gets aliases to the repository's library files. | ||
|
||
### Running the sample | ||
|
||
All samples get packaged into a single docker image, based on the [`Dockerfile`](./Dockerfile) in this directory. | ||
|
||
The `Dockerfile` gets built from the context of the [`backend-deno`](../) directory. This is done to ensure it has access to the repository's library `mod.ts` file. | ||
|
||
To add your sample to the `docker-compose.yml` file, add the following to the `services` section: | ||
|
||
```yaml | ||
<service-name>: | ||
build: | ||
context: ../ | ||
dockerfile: samples/Dockerfile | ||
command: ["<service-name>/mod.ts"] | ||
depends_on: | ||
- nats | ||
env_file: | ||
- .common.env | ||
``` | ||
Replace `<service-name>` with the name of your sample. For example, if your sample is named `hello_world`, replace `<service-name>` with `hello_world`. | ||
|
||
You then have to rebuild the docker image by running the following command from the `samples` directory: | ||
|
||
```bash | ||
docker compose up --build | ||
``` | ||
|
||
## Docker Image publishing | ||
|
||
The docker image may, in the future, be published to a docker registry. | ||
|
||
This way, projects can easily include the samples in their `docker-compose.yml` file without having to download them locally in their projects for useful services. |
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,13 @@ | ||
FROM denoland/deno:alpine-1.39.0 | ||
LABEL version="1.0.0-alpha.3" maintainer="WüSpace e. V. <[email protected]>" | ||
|
||
# Add files | ||
COPY ./mod.ts /app/mod.ts | ||
COPY ./samples /app/samples | ||
|
||
# Cache dependencies in container layer | ||
RUN deno cache /app/samples/**/*.ts | ||
|
||
# Run | ||
WORKDIR /app/samples | ||
ENTRYPOINT [ "deno", "run", "--allow-all" ] |
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,19 @@ | ||
# Service Configuration Sample | ||
|
||
This sample shows how to use the configuration system. | ||
|
||
In addition to parsing the config for further use, | ||
all configuration options are printed to the console. | ||
|
||
## Configuration Options | ||
|
||
The following configuration options get printed to the console: | ||
|
||
### Standard Configuration Options | ||
|
||
- `SERVICE_NAME` | ||
- `DATA_DIR` | ||
|
||
### Custom Configuration Options | ||
|
||
- `MY_STRING` |
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,24 @@ | ||
import {startService} from "https://deno.land/x/telestion/mod.ts"; | ||
import {z} from "https://deno.land/x/[email protected]/mod.ts"; | ||
|
||
// Start the service | ||
const {config, serviceName, dataDir} = await startService({ | ||
nats: false // we don't need NATS to work with the config | ||
}); | ||
|
||
// Standard config options | ||
console.log(`Service "${serviceName}" started!`); | ||
console.log(`Data directory: ${dataDir}`); | ||
|
||
// Custom config options | ||
const customConfig = z.object({ | ||
MY_STRING: z.string(), | ||
}).parse(config); | ||
|
||
console.log(`My string: ${customConfig.MY_STRING}`); | ||
|
||
// Everything | ||
console.log("Complete config: ", config); | ||
|
||
// The end | ||
console.log("Stopping service...") |
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,5 @@ | ||
{ | ||
"imports": { | ||
"https://deno.land/x/telestion/mod.ts": "../mod.ts" | ||
} | ||
} |
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,70 @@ | ||
services: | ||
nats: | ||
image: nats:latest | ||
ports: | ||
- "4222:4222" | ||
- "8222:8222" | ||
# volumes: | ||
# - ./nats.conf:/etc/nats.conf | ||
config: | ||
build: | ||
context: ../ | ||
dockerfile: samples/Dockerfile | ||
command: ["config/mod.ts", "--MY_STRING", "Overwritten Hello World"] | ||
depends_on: | ||
- nats | ||
env_file: | ||
- .common.env | ||
environment: | ||
- SERVICE_NAME=config | ||
- MY_STRING=Hello World that gets overwritten | ||
latest-value-cache: | ||
build: | ||
context: ../ | ||
dockerfile: samples/Dockerfile | ||
command: ["latest-value-cache/mod.ts"] | ||
depends_on: | ||
- nats | ||
env_file: | ||
- .common.env | ||
environment: | ||
- SERVICE_NAME=latest-value-cache | ||
- DATA_SUBJECT=data.> | ||
- REQUEST_SUBJECT=latest.data.> | ||
sample-publisher: | ||
build: | ||
context: ../ | ||
dockerfile: samples/Dockerfile | ||
command: ["publisher/mod.ts"] | ||
depends_on: | ||
- nats | ||
env_file: | ||
- .common.env | ||
environment: | ||
- SERVICE_NAME=sample-publisher | ||
- DATA_SUBJECT=data.sample | ||
forward-to-logger: | ||
build: | ||
context: ../ | ||
dockerfile: samples/Dockerfile | ||
command: ["requester/mod.ts"] | ||
depends_on: | ||
- nats | ||
env_file: | ||
- .common.env | ||
environment: | ||
- SERVICE_NAME=forward-to-logger | ||
- REQUEST_SUBJECT=latest.data.sample | ||
- FREQUENCY=3000 | ||
- OUTPUT_SUBJECT=log.sample-data | ||
logger: | ||
build: | ||
context: ../ | ||
dockerfile: samples/Dockerfile | ||
command: ["logger/mod.ts"] | ||
depends_on: | ||
- nats | ||
env_file: | ||
- .common.env | ||
environment: | ||
- SERVICE_NAME=logger |
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,20 @@ | ||
# Latest Value Cache | ||
|
||
A cache that stores the latest value for a given subject namespace (`[prefix].>`) and enables other services to retrieve the latest value for a given subject. | ||
|
||
## Configuration Options | ||
|
||
| Option | Description | Default | | ||
| ------ | ----------- | ------- | | ||
| `DATA_SUBJECT` | The subject namespace to cache values for. Must be of the pattern `[data-prefix].>` | (required) | | ||
| `REQUEST_SUBJECT` | The subject to listen for requests on. Must be of the pattern `[request-prefix].>` | (required) | | ||
|
||
Note that the `DATA_SUBJECT` and `REQUEST_SUBJECT` must be different. For each subject in the specified `DATA_SUBJECT` namespace, the latest value will be stored in the cache. Other services can then request the latest value for a given subject by publishing a message to the `REQUEST_SUBJECT` namespace with the subject to request as the message payload. | ||
|
||
## Limitations | ||
|
||
The cache is not persistent, so if the service is restarted, the cache will be empty. | ||
|
||
While the service can be scaled horizontally (and requests will be load balanced across all instances), new data gets handled by all instances. | ||
|
||
This could be improved by using a distributed cache (e.g. Redis). |
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,65 @@ | ||
import { startService } from "https://deno.land/x/telestion/mod.ts"; | ||
import { z } from "https://deno.land/x/[email protected]/mod.ts"; | ||
|
||
const { messageBus, config, serviceName } = await startService(); | ||
|
||
const { DATA_SUBJECT, REQUEST_SUBJECT } = z.object({ | ||
DATA_SUBJECT: z.string().endsWith(">"), | ||
REQUEST_SUBJECT: z.string().endsWith(">"), | ||
}).parse(config); | ||
|
||
console.log("Latest value cache started with config", { | ||
DATA_SUBJECT, | ||
REQUEST_SUBJECT, | ||
}); | ||
|
||
const dataStore = new Map<string, Uint8Array>(); | ||
|
||
console.log("Listening for new data on", DATA_SUBJECT); | ||
|
||
// listen to the data subject | ||
const data = messageBus.subscribe(DATA_SUBJECT); | ||
(async () => { | ||
for await (const msg of data) { | ||
// data key is the ">" in the subject | ||
const dataKey = msg.subject.substring(DATA_SUBJECT.length - 1); | ||
// store the data | ||
dataStore.set(dataKey, msg.data); | ||
|
||
console.log( | ||
"Latest value cache received data", | ||
msg.data, | ||
"for key", | ||
dataKey, | ||
); | ||
} | ||
})(); | ||
|
||
// listen to the request subject | ||
const request = messageBus.subscribe(REQUEST_SUBJECT, { | ||
queue: serviceName, | ||
}); | ||
(async () => { | ||
for await (const msg of request) { | ||
console.log("Latest value cache received request on", msg.subject); | ||
|
||
// request key is the ">" in the subject | ||
const requestKey = msg.subject.substring(REQUEST_SUBJECT.length - 1); | ||
// get the data from the store | ||
const data = dataStore.get(requestKey); | ||
// respond with the data or null if there is no data | ||
msg.respond(data); | ||
|
||
console.log( | ||
"Latest value cache responded with", | ||
data, | ||
"for key", | ||
requestKey, | ||
); | ||
} | ||
})(); | ||
|
||
await Promise.any([data.closed, request.closed]); | ||
console.log("Latest value cache stopped"); | ||
data.drain(); | ||
request.drain(); |
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,11 @@ | ||
# Logger Sample Service | ||
|
||
This sample service demonstrates how to use the Telestion library to create a simple logger service. | ||
|
||
It's equivalent to the [example in the documentation](https://docs.telestion.wuespace.de/Backend%20Development/typescript/e2e-log-service/). | ||
|
||
## Functionality Description | ||
|
||
Logs all messages received on any "sub-subject" of `log.>`. For example, if a message is received on `log.info`, it will be logged. If a message is received on `log.debug`, it will also be logged. | ||
|
||
Messages get logged on both the console and to a local file. |
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,27 @@ | ||
import { startService } from "https://deno.land/x/telestion/mod.ts"; | ||
import { encode } from "https://deno.land/[email protected]/encoding/hex.ts"; | ||
|
||
const encoder = new TextEncoder(); | ||
|
||
const { messageBus } = await startService(); | ||
|
||
const logMessages = messageBus.subscribe("log.>"); | ||
|
||
console.log("Logger started"); | ||
|
||
for await (const msg of logMessages) { | ||
try { | ||
const currentTime = new Date().toISOString(); | ||
const logMessage = encode(msg.data).toString(); | ||
const subject = msg.subject.split(".")[1]; | ||
|
||
console.log(`${currentTime} [${subject}] ${logMessage}`); | ||
await Deno.writeFile( | ||
"log.txt", | ||
encoder.encode(`${currentTime} [${subject}] ${logMessage}\n`), | ||
{ append: true }, | ||
); | ||
} catch (error) { | ||
console.error(error); | ||
} | ||
} |
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,12 @@ | ||
# Publisher Sample | ||
|
||
This sample publishes a random JSON message in a given frequency. | ||
|
||
## Configuration Options | ||
|
||
The following configuration options are available: | ||
|
||
| Option | Description | Default | | ||
| ------ | ----------- | ------- | | ||
| `DATA_SUBJECT` | The data subject to publish messages to | (required) | | ||
| `FREQUENCY` | The frequency in which to publish messages (in milliseconds) | `3000` | |
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,26 @@ | ||
import { JSONCodec, startService } from "https://deno.land/x/telestion/mod.ts"; | ||
import { z } from "https://deno.land/x/[email protected]/mod.ts"; | ||
|
||
const { messageBus, config } = await startService(); | ||
|
||
const { DATA_SUBJECT, FREQUENCY } = z.object({ | ||
DATA_SUBJECT: z.string(), | ||
FREQUENCY: z.coerce.number().positive().default(3000), | ||
}).parse(config); | ||
|
||
console.log("Publisher started with config", { | ||
DATA_SUBJECT, | ||
}); | ||
|
||
setInterval(() => { | ||
const value = { | ||
value: Math.random(), | ||
time: new Date().toISOString(), | ||
}; | ||
console.log("Publishing", value, "to", DATA_SUBJECT); | ||
messageBus.publish( | ||
DATA_SUBJECT, | ||
JSONCodec().encode(value), | ||
); | ||
console.log("Published", value, "to", DATA_SUBJECT); | ||
}, FREQUENCY); |
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,13 @@ | ||
# Requester Sample | ||
|
||
This sample shows how to request data from another service. | ||
|
||
In a given frequency, the service will request the value from a given subject (with an empty request) and re-publish it on a different subject. | ||
|
||
## Configuration Options | ||
|
||
| Option | Description | Default | | ||
| ------ | ----------- | ------- | | ||
| `REQUEST_SUBJECT` | The subject to request data from. | (required) | | ||
| `PUBLISH_SUBJECT` | The subject to publish the requested data on. | (required) | | ||
| `FREQUENCY` | The frequency to request data from the `REQUEST_SUBJECT` in milliseconds. | `5000` | |
Oops, something went wrong.