[WASM] Redis Trigger のアプリを試す [Spin]

2022.06.03

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Introduction

ここではHttpトリガーのプロジェクトを作成したので、
今回はRedisトリガーのプロジェクトを作成します。

Redisトリガーのプロジェクトでは、
任意のRedis Channelに対して、データがpublishされたタイミングで
Spinのコンポーネントを実行させることができます。

Env

  • MacBook Pro (13-inch, M1, 2020)
  • OS : MacOS 11.3.1
  • rust : 1.61.0
  • redis : 7.0.0

Setup

まずはRedisをインストールします。
Homebrewでインストール可能です。

% brew install redis

Redisを起動させておきます。

% redis-server 
or
% brew services start redis

Try

Httpトリガーのプロジェクト(spin-http)と
Redisトリガーのプロジェクト(spin-redis)を作成します。

spin-httpdeではHTTPのクエリパラメータで指定した文字列を
ローカルのRedisへpublishします。
spin-redisではRedisにデータがpublishされたタイミングで
コンポーネントが起動し、そのデータをログに出力するようにします。

Create Redis Trigger Project

まずはRedisトリガーのプロジェクトを作成します。
spin newコマンドでredis-rustタイプのプロジェクトを作成します。

% spin new redis-rust
・・・

spin.tomlはデフォルトのままでOKです。
localhost:6379のRedis(channelはmessages)に対して
データがpublishされるとコンポーネントが起動します。

spin_version = "1"
authors = ["someone"]
description = "spin redis"
name = "spin-redis"
trigger = { type = "redis", address = "redis://localhost:6379" }
version = "0.1.0"

[[component]]
id = "spin-redis"
source = "target/wasm32-wasi/release/spin_redis.wasm"
[component.trigger]
channel = "messages"
[component.build]
command = "cargo build --target wasm32-wasi --release"

lib.rsではprintln!でうけとったデータを出力しています。
結果は~/.spin/<Project名>/logsのログファイルに出力されます。

use anyhow::Result;
use bytes::Bytes;
use spin_sdk::redis_component;
use std::str::from_utf8;

#[redis_component]
fn on_message(message: Bytes) -> Result<()> {
    println!("{}", from_utf8(&message)?);
    Ok(())
}

spun upして動作確認してみます。

% cd path/your/spin-redis
% spin build --up
Executing the build command for component spin-redis: cargo build --target wasm32-wasi --release
    Finished release [optimized] target(s) in 0.82s
Successfully ran the build command for the Spin components.
2022-06-03T08:27:29.305761Z TRACE build: spin_engine: Created module for component spin-redis from file 2022-06-03T08:27:29.305787Z TRACE build: spin_engine: Created pre-instance from module for component spin-redis.
2022-06-03T08:27:29.305790Z TRACE build: spin_engine: Execution context initialized.
2022-06-03T08:27:29.305880Z  INFO spin_redis_engine: Connecting to Redis server at redis://localhost:6379
2022-06-03T08:27:29.307808Z  INFO spin_redis_engine: Subscribed component #0 (spin-redis) to channel: messages

redis-cliでメッセージをpublishしてみます。

% redis-cli
127.0.0.1:6379> publish messages "hello from redis-cli"
(integer) 1

spin-redisのログ(私の環境では~/.spin/spin-redis/logs/spin-redis_stdout.txt)
をみてみると、publishした文字列が記述されています。 

Create Http Trigger Project

次にHttpトリガーのSpinアプリを作成し、/publishリクエスト時に
Redisへpublishするようにします。

Httpトリガーのプロジェクトを作成。

% spin new http-rust

spin.tomlは下記。
environmentを使うと、spin.tomlで定義した値を
コンポーネントで使えます。

  spin_version = "1"
  authors = ["someone"]
  description = "spin http project"
  name = "spin-http"
  trigger = { type = "http", base = "/" }
  version = "0.1.0"

  [[component]]
  environment = { REDIS_ADDRESS = "redis://localhost:6379", REDIS_CHANNEL = "messages" }
  id = "spin-http"
  source = "target/wasm32-wasi/release/spin_http.wasm"
  [component.trigger]
  route = "/publish"
  [component.build]
  command = "cargo build --target wasm32-wasi --release"

コンポーネントではクエリ文字列を取得して
Redisにpublishしてます。
なお、constで定義している変数はspin.tomlで定義した値に置き換えられます。

use anyhow::{Result};
use spin_sdk::{
    http::{internal_server_error, Request, Response},
    http_component, redis,
};

const REDIS_ADDRESS_ENV: &str = "REDIS_ADDRESS";
const REDIS_CHANNEL_ENV: &str = "REDIS_CHANNEL";

#[http_component]
fn publish(req: Request) -> Result<Response> {
    let address = std::env::var(REDIS_ADDRESS_ENV)?;
    let channel = std::env::var(REDIS_CHANNEL_ENV)?;

    //get query string
    let param = match req.uri().query() {
        Some(p) if p.len() > 0 => p.as_bytes(),
        _ => "Foo".as_bytes(),
    };

    println!("{:?}",param);

    // Publish to Redis
    match redis::publish(&address, &channel, &param) {
        Ok(()) => Ok(http::Response::builder().status(200).body(Some("OK".into()))?),
        Err(_e) => internal_server_error(),
    }
}

spin upで起動します。

% cd path/your/spin-http
% spin build --up
Executing the build command for component spin-http: cargo build --target wasm32-wasi --release
   Compiling spin-http v0.1.0 
    Finished release [optimized] target(s) in 0.92s
Successfully ran the build command for the Spin components.
Serving HTTP on address http://127.0.0.1:3000
Available Routes:
  spin-http: http://127.0.0.1:3000/publish

クエリ文字列をつけて/publishにリクエストします。

% curl -i http://localhost:3000/publish?redis-trigger-from-http
HTTP/1.1 200 OK
content-length: 2
date: Fri, 03 Jun 2022 08:42:20 GMT

OK

spin-redis_stdout.txtを見ると、
クエリ文字列が記録されているのがわかります。

Summary

というわけで、SpinのRedisトリガーを試してみました。
次はRedisをAmazon MemoryDB for Redis にしてみて動くか確認する(かもしれない)。

References