Skip to content

Commit f0a2afc

Browse files
committed
Documentation + agent context.
1 parent 9fe73fa commit f0a2afc

File tree

10 files changed

+951
-4
lines changed

10 files changed

+951
-4
lines changed

context/getting-started.md

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
# Getting Started
2+
3+
This guide explains how to get started with `async-service` to create and run services in Ruby.
4+
5+
## Installation
6+
7+
Add the gem to your project:
8+
9+
```bash
10+
$ bundle add async-service
11+
```
12+
13+
## Core Concepts
14+
15+
`async-service` has several core concepts:
16+
17+
- A {ruby Async::Service::Generic} which represents the base class for implementing services.
18+
- A {ruby Async::Service::Configuration} which manages service configurations and environments.
19+
- A {ruby Async::Service::Controller} which handles starting, stopping, and managing services.
20+
21+
## Usage
22+
23+
Services are long-running processes that can be managed as a group. Each service extends `Async::Service::Generic` and implements a `setup` method that defines how the service runs.
24+
25+
### Basic Service
26+
27+
Create a simple service that runs continuously:
28+
29+
```ruby
30+
#!/usr/bin/env async-service
31+
32+
require 'async/service'
33+
34+
class HelloService < Async::Service::Generic
35+
def setup(container)
36+
super
37+
38+
container.run(count: 1, restart: true) do |instance|
39+
instance.ready!
40+
41+
while true
42+
puts "Hello World!"
43+
sleep 1
44+
end
45+
end
46+
end
47+
end
48+
49+
service "hello" do
50+
service_class HelloService
51+
end
52+
```
53+
54+
Make the file executable and run it:
55+
56+
```bash
57+
$ chmod +x hello_service.rb
58+
$ ./hello_service.rb
59+
```
60+
61+
### Service Configuration
62+
63+
Services can be configured with custom properties:
64+
65+
```ruby
66+
service "web-server" do
67+
service_class WebServerService
68+
port 3000
69+
host "localhost"
70+
end
71+
```
72+
73+
In your service implementation, you can access these values through the environment and evaluator:
74+
75+
```ruby
76+
class WebServerService < Async::Service::Generic
77+
def setup(container)
78+
super
79+
80+
container.run(count: 1, restart: true) do |instance|
81+
# Access the configuration for the service:
82+
evaluator = self.environment.evaluator
83+
port = evaluator.port
84+
host = evaluator.host
85+
86+
puts "Starting web server on #{host}:#{port}"
87+
instance.ready!
88+
89+
# Your web server implementation here
90+
end
91+
end
92+
end
93+
```
94+
95+
### Multiple Services
96+
97+
You can define multiple services in a single configuration file:
98+
99+
```ruby
100+
#!/usr/bin/env async-service
101+
102+
require 'async/service'
103+
104+
class WebService < Async::Service::Generic
105+
def setup(container)
106+
super
107+
108+
container.run(count: 1, restart: true) do |instance|
109+
instance.ready!
110+
puts "Web service starting..."
111+
# Web server implementation
112+
end
113+
end
114+
end
115+
116+
class WorkerService < Async::Service::Generic
117+
def setup(container)
118+
super
119+
120+
container.run(count: 2, restart: true) do |instance|
121+
instance.ready!
122+
puts "Worker #{instance.name} starting..."
123+
# Background job processing
124+
end
125+
end
126+
end
127+
128+
service "web" do
129+
service_class WebService
130+
port 3000
131+
host "localhost"
132+
end
133+
134+
service "worker" do
135+
service_class WorkerService
136+
end
137+
```
138+
139+
### Programmatic Usage
140+
141+
You can also create and run services programmatically:
142+
143+
```ruby
144+
require 'async/service'
145+
146+
configuration = Async::Service::Configuration.build do
147+
service "my-service" do
148+
service_class MyService
149+
end
150+
end
151+
152+
Async::Service::Controller.run(configuration)
153+
```
154+
155+
### Accessing Configuration Values
156+
157+
Services have access to their configuration through the environment and evaluator:
158+
159+
```ruby
160+
class ConfigurableService < Async::Service::Generic
161+
def setup(container)
162+
super
163+
164+
container.run(count: 1, restart: true) do |instance|
165+
# Clone the evaluator for thread safety
166+
evaluator = self.environment.evaluator
167+
database_url = evaluator.database_url
168+
max_connections = evaluator.max_connections
169+
debug_mode = evaluator.debug_mode
170+
171+
puts "Database URL: #{database_url}"
172+
puts "Max connections: #{max_connections}"
173+
puts "Debug mode: #{debug_mode}"
174+
175+
instance.ready!
176+
177+
# Your service implementation using these values
178+
end
179+
end
180+
end
181+
182+
service "configurable" do
183+
service_class ConfigurableService
184+
database_url "postgresql://localhost/myapp"
185+
max_connections 10
186+
debug_mode true
187+
end
188+
```
189+
190+
The evaluator is a memoized instance of the service's configuration, allowing for efficient access to configuration values throughout the service's lifecycle.

context/index.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Automatically generated context index for Utopia::Project guides.
2+
# Do not edit then files in this directory directly, instead edit the guides and then run `bake utopia:project:agent:context:update`.
3+
---
4+
description: A service layer for Async.
5+
metadata:
6+
documentation_uri: https://socketry.github.io/async-service/
7+
source_code_uri: https://github.com/socketry/async-service.git
8+
files:
9+
- path: getting-started.md
10+
title: Getting Started
11+
description: This guide explains how to get started with `async-service` to create
12+
and run services in Ruby.

examples/hello/readme.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Hello Service Example
2+
3+
This example demonstrates the most basic usage of Async::Service - creating a simple service that prints "Hello World!" every second.
4+
5+
## Running the Example
6+
7+
Make the file executable and run it:
8+
9+
~~~ bash
10+
$ chmod +x hello.rb
11+
$ ./hello.rb
12+
~~~
13+
14+
You should see output like this:
15+
16+
```
17+
Hello World!
18+
Hello World!
19+
Hello World!
20+
...
21+
```
22+
23+
Press `Ctrl+C` to stop the service.
24+
25+
## How it Works
26+
27+
The example defines a simple service class:
28+
29+
~~~ ruby
30+
class SleepService < Async::Service::Generic
31+
def setup(container)
32+
super
33+
34+
container.run(count: 1, restart: true) do |instance|
35+
instance.ready!
36+
37+
while true
38+
puts "Hello World!"
39+
sleep 1
40+
end
41+
end
42+
end
43+
end
44+
~~~
45+
46+
Key points:
47+
48+
- **Inherits from `Async::Service::Generic`**: Provides the basic service interface
49+
- **Implements `setup(container)`**: Defines how the service runs
50+
- **Uses `container.run`**: Creates one instance with automatic restart
51+
- **Calls `instance.ready!`**: Signals the service is ready
52+
- **Contains the main loop**: The actual service logic
53+
54+
The service is then configured and made available for execution:
55+
56+
~~~ ruby
57+
service "sleep" do
58+
service_class SleepService
59+
end
60+
~~~
61+
62+
## What's Next?
63+
64+
Try modifying the example:
65+
66+
- Change the message that gets printed
67+
- Adjust the sleep interval
68+
- Add multiple instances by changing `count: 1` to `count: 3`
69+
- Add environment variables or configuration
70+
71+
For more complex examples, check out the [Getting Started Guide](../../guides/getting-started/).

0 commit comments

Comments
 (0)