Skip to content

Commit 5376262

Browse files
authored
Merge pull request #29 from mrubyedge/queue-generator
Cloudflare Queue consumer generator
2 parents 6983cd2 + 5a0a07a commit 5376262

26 files changed

Lines changed: 1848 additions & 26 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

uzumibi-cli/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "uzumibi-cli"
3-
version = "0.6.0-rc1"
3+
version = "0.6.0-rc2"
44
edition = "2024"
55
authors = ["Uchio Kondo <udzura@udzura.jp>"]
66
description = "Uzumibi CLI tool to generate serverless mruby/edge apps"

uzumibi-cli/src/main.rs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,12 @@ fn create_project(
9191
println!("Creating project '{}'...", project_name);
9292

9393
// Collect feature overlay paths to know which files to skip from base
94-
let feature_files = collect_feature_overlay_files(template, features);
94+
let mut feature_files = collect_feature_overlay_files(template, features);
95+
96+
// When queue feature is active, skip app.rb (consumer.rb replaces it)
97+
if features.iter().any(|f| f == "queue") {
98+
feature_files.insert("lib/app.rb".to_string());
99+
}
95100

96101
// Copy base template files (skip files that will be overridden by feature overlays)
97102
copy_dir_recursive(
@@ -338,14 +343,17 @@ fn show_diff(existing_file: &Path, new_content: &[u8]) -> Result<(), Box<dyn std
338343

339344
fn substitute_project_name(content: &str, project_name: &str) -> String {
340345
let project_name_underscore = project_name.replace('-', "_");
346+
let project_name_kebab = project_name.replace('_', "-");
341347

342348
content
343349
.replace("$$PROJECT_NAME$$", project_name)
344350
.replace("$$PROJECT_NAME_UNDERSCORE$$", &project_name_underscore)
351+
.replace("$$PROJECT_NAME_KEBAB$$", &project_name_kebab)
345352
}
346353

347354
fn print_project_next_steps(template: &str, project_name: &str, features: &[String]) {
348355
let has_enable_external = features.iter().any(|f| f == "enable-external");
356+
let has_queue = features.iter().any(|f| f == "queue");
349357

350358
println!("\nNext steps:");
351359
match template {
@@ -358,7 +366,7 @@ fn print_project_next_steps(template: &str, project_name: &str, features: &[Stri
358366
println!(" \x1b[36mrustup target add wasm32-unknown-unknown\x1b[0m");
359367
println!(" • Node.js tools:");
360368
println!(" \x1b[36mnpm install -g pnpm wrangler\x1b[0m");
361-
if has_enable_external {
369+
if has_enable_external || has_queue {
362370
println!(" • wasm-opt (Binaryen, required for asyncify):");
363371
println!(" \x1b[36mbrew install binaryen\x1b[0m");
364372
println!(" Or visit: https://github.com/WebAssembly/binaryen/releases");
@@ -370,7 +378,28 @@ fn print_project_next_steps(template: &str, project_name: &str, features: &[Stri
370378
println!(" \x1b[36mpnpm run dev\x1b[0m");
371379
println!(" 3. Deploy to Cloudflare:");
372380
println!(" \x1b[36mpnpm run deploy\x1b[0m");
373-
if has_enable_external {
381+
if has_queue {
382+
println!();
383+
println!(
384+
" \x1b[33mNote:\x1b[0m This project uses queue feature (Cloudflare Queues consumer)."
385+
);
386+
println!(
387+
" Edit \x1b[36mlib/consumer.rb\x1b[0m to implement your queue consumer logic."
388+
);
389+
println!(" The following Uzumibi APIs are available in Ruby:");
390+
println!(
391+
" • \x1b[36mUzumibi::Message#ack!\x1b[0m / \x1b[36m#retry(delay_seconds: N)\x1b[0m → Message control"
392+
);
393+
println!(
394+
" • \x1b[36mUzumibi::Fetch.fetch(url, method, body)\x1b[0m → Uzumibi::Response"
395+
);
396+
println!(
397+
" • \x1b[36mUzumibi::KV.get(key)\x1b[0m / \x1b[36mUzumibi::KV.set(key, value)\x1b[0m → Durable Object storage"
398+
);
399+
println!(
400+
" • \x1b[36mUzumibi::Queue.send(queue_name, message)\x1b[0m → Cloudflare Queue"
401+
);
402+
} else if has_enable_external {
374403
println!();
375404
println!(" \x1b[33mNote:\x1b[0m This project uses enable-external feature.");
376405
println!(" The following Uzumibi APIs are available in Ruby:");

uzumibi-cli/templates/cloudflare/__features__/enable-external/wrangler.jsonc

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,21 @@
1010
"observability": {
1111
"enabled": true
1212
},
13+
/**
14+
* Queues
15+
* Used for Uzumibi::Queue.send
16+
* Uncomment the following block to enable queue producer capabilities.
17+
* And create queue via command wrangler queue create $$PROJECT_NAME_KEBAB$$-queue
18+
* https://developers.cloudflare.com/queues/
19+
*/
20+
// "queues": {
21+
// "producers": [
22+
// {
23+
// "binding": "UZUMIBI_QUEUE",
24+
// "queue": "$$PROJECT_NAME_KEBAB$$-queue"
25+
// }
26+
// ]
27+
// },
1328
/**
1429
* Durable Objects
1530
* Used for Uzumibi::KV.get/set
@@ -31,17 +46,4 @@
3146
]
3247
}
3348
]
34-
/**
35-
* Queues
36-
* Used for Uzumibi::Queue.send
37-
* https://developers.cloudflare.com/queues/
38-
*/
39-
// "queues": {
40-
// "producers": [
41-
// {
42-
// "binding": "MY_QUEUE",
43-
// "queue": "my-queue-name"
44-
// }
45-
// ]
46-
// }
4749
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
class Consumer < Uzumibi::Consumer
2+
# @rbs message: Uzumibi::Message
3+
def on_receive(message)
4+
debug_console("[Consumer] Received message: id=#{message.id}, body=#{message.body}, attempts=#{message.attempts}")
5+
6+
if message.attempts > 3
7+
debug_console("[Consumer] Acknowledging message #{message.id} after 3 attempts!!")
8+
message.ack!
9+
else
10+
message.retry(delay_seconds: 3)
11+
end
12+
end
13+
end
14+
15+
$CONSUMER = Consumer.new
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "$$PROJECT_NAME$$",
3+
"version": "0.0.0",
4+
"private": true,
5+
"scripts": {
6+
"deploy": "npm run build:wasm:asyncify && wrangler deploy",
7+
"dev": "npm run build:wasm:asyncify && wrangler dev",
8+
"build:wasm:asyncify": "cargo build --package $$PROJECT_NAME$$ --target wasm32-unknown-unknown --release --features queue && wasm-opt --enable-bulk-memory --enable-nontrapping-float-to-int --asyncify -O2 target/wasm32-unknown-unknown/release/$$PROJECT_NAME_UNDERSCORE$$.wasm -o ./src/$$PROJECT_NAME_UNDERSCORE$$_queue.wasm",
9+
"start": "wrangler dev",
10+
"test": "vitest"
11+
},
12+
"devDependencies": {
13+
"@cloudflare/vitest-pool-workers": "^0.8.19",
14+
"asyncify-wasm": "^1.2.0",
15+
"vitest": "~3.2.0",
16+
"wrangler": "^4.54.0"
17+
}
18+
}

0 commit comments

Comments
 (0)