<html lang="en">
<head></head>
<body>

<form id="mainForm" method="post" action="https://stackblitz.com/run" target="_self">
<input type="hidden" name="project[files][README.md]" value="# Redis Example for RivetKit

Example project demonstrating Redis persistence and coordinate topology with [RivetKit](https://rivetkit.org).

[Learn More →](https://github.com/rivet-gg/rivetkit)

[Discord](https://rivet.gg/discord) — [Documentation](https://rivetkit.org) — [Issues](https://github.com/rivet-gg/rivetkit/issues)

## Getting Started

### Prerequisites

- Node.js 18+
- Redis server running on localhost:6379 (or configure connection)

### Installation

```sh
git clone https://github.com/rivet-gg/rivetkit
cd rivetkit/examples/redis
npm install
```

### Development

Start Redis server (if not already running):
```sh
redis-server
```

Start the RivetKit server:
```sh
npm run dev
```

In another terminal, run the client demo:
```sh
npm run client
```

## Configuration

The example uses Redis with coordinate topology, which provides:
- **Persistence**: Actor state is stored in Redis
- **Coordination**: Multiple server instances can coordinate through Redis
- **Scalability**: Actors can migrate between nodes based on load

### Environment Variables

- `REDIS_HOST`: Redis server host (default: localhost)
- `REDIS_PORT`: Redis server port (default: 6379)
- `REDIS_PASSWORD`: Redis password (if required)
- `REDIS_DB`: Redis database number (default: 0)

### Example with custom Redis configuration:

```sh
REDIS_HOST=redis.example.com REDIS_PORT=6380 REDIS_PASSWORD=secret npm run dev
```

## Features Demonstrated

- **Redis Actor Driver**: Persists actor state in Redis
- **Redis Manager Driver**: Handles actor discovery and routing
- **Redis Coordinate Driver**: Enables peer-to-peer coordination between nodes
- **State Persistence**: Counter state survives server restarts
- **Action Execution**: Remote procedure calls with Redis backend
- **Broadcasting**: Events sent to connected clients

## License

Apache 2.0">
<input type="hidden" name="project[files][package.json]" value="{&quot;name&quot;:&quot;example-redis&quot;,&quot;version&quot;:&quot;0.9.9&quot;,&quot;private&quot;:true,&quot;type&quot;:&quot;module&quot;,&quot;scripts&quot;:{&quot;dev&quot;:&quot;tsx --watch src/server.ts&quot;,&quot;check-types&quot;:&quot;tsc --noEmit&quot;,&quot;client&quot;:&quot;tsx scripts/client.ts&quot;},&quot;devDependencies&quot;:{&quot;@types/node&quot;:&quot;^22.13.9&quot;,&quot;@rivetkit/actor&quot;:&quot;https://pkg.pr.new/rivet-gg/rivetkit/@rivetkit/actor@27b9131c5788cdf2007730353b43b33a296aedf3&quot;,&quot;tsx&quot;:&quot;^3.12.7&quot;,&quot;typescript&quot;:&quot;^5.7.3&quot;},&quot;dependencies&quot;:{&quot;@rivetkit/redis&quot;:&quot;https://pkg.pr.new/rivet-gg/rivetkit/@rivetkit/redis@27b9131c5788cdf2007730353b43b33a296aedf3&quot;,&quot;ioredis&quot;:&quot;^5.4.1&quot;,&quot;zod&quot;:&quot;^3.25.76&quot;},&quot;stableVersion&quot;:&quot;0.8.0&quot;}">
<input type="hidden" name="project[files][tsconfig.json]" value="{
  &quot;compilerOptions&quot;: {
    &quot;target&quot;: &quot;esnext&quot;,
    &quot;lib&quot;: [&quot;esnext&quot;],
    &quot;module&quot;: &quot;esnext&quot;,
    &quot;moduleResolution&quot;: &quot;bundler&quot;,
    &quot;types&quot;: [&quot;node&quot;],
    &quot;resolveJsonModule&quot;: true,
    &quot;allowJs&quot;: true,
    &quot;checkJs&quot;: false,
    &quot;noEmit&quot;: true,
    &quot;isolatedModules&quot;: true,
    &quot;allowSyntheticDefaultImports&quot;: true,
    &quot;forceConsistentCasingInFileNames&quot;: true,
    &quot;strict&quot;: true,
    &quot;skipLibCheck&quot;: true
  },
  &quot;include&quot;: [&quot;src/**/*&quot;, &quot;scripts/**/*&quot;]
}
">
<input type="hidden" name="project[files][turbo.json]" value="{
  &quot;$schema&quot;: &quot;https://turbo.build/schema.json&quot;,
  &quot;extends&quot;: [&quot;//&quot;]
}
">
<input type="hidden" name="project[files][scripts/client.ts]" value="import { createClient } from &quot;@rivetkit/actor/client&quot;;
import type { registry } from &quot;../src/registry&quot;;

const client = createClient&lt;typeof registry&gt;(&quot;http://localhost:8088&quot;);

async function main() {
	console.log(&quot;Redis Example Client&quot;);
	console.log(&quot;===================&quot;);

	// Create a counter actor
	const counter = client.counter.getOrCreate(&quot;my-counter&quot;);

	// Get initial count
	const initialCount = await counter.getCount();
	console.log(`Initial count: ${initialCount}`);

	// Increment the counter
	console.log(&quot;Incrementing by 5...&quot;);
	const newCount = await counter.increment(5);
	console.log(`New count: ${newCount}`);

	// Increment again
	console.log(&quot;Incrementing by 3...&quot;);
	const finalCount = await counter.increment(3);
	console.log(`Final count: ${finalCount}`);

	// Reset the counter
	console.log(&quot;Resetting counter...&quot;);
	const resetCount = await counter.reset();
	console.log(`Reset count: ${resetCount}`);

	// Create another counter to demonstrate persistence
	const counter2 = client.counter.getOrCreate(&quot;another-counter&quot;);
	console.log(&quot;Incrementing second counter by 10...&quot;);
	const count2 = await counter2.increment(10);
	console.log(`Second counter: ${count2}`);

	console.log(&quot;\nDemo complete! The counter state is persisted in Redis.&quot;);
	console.log(&quot;You can restart the server and the state will be preserved.&quot;);
}

main().catch(console.error);
">
<input type="hidden" name="project[files][src/registry.ts]" value="import { actor, setup } from &quot;@rivetkit/actor&quot;;

const counter = actor({
	state: { count: 0 },
	actions: {
		increment: (c, x: number) =&gt; {
			c.state.count += x;
			c.broadcast(&quot;newCount&quot;, c.state.count);
			return c.state.count;
		},
		getCount: (c) =&gt; {
			return c.state.count;
		},
		reset: (c) =&gt; {
			c.state.count = 0;
			c.broadcast(&quot;newCount&quot;, c.state.count);
			return c.state.count;
		},
	},
});

export const registry = setup({
	use: { counter },
});
">
<input type="hidden" name="project[files][src/server.ts]" value="import { createRedisDriver } from &quot;@rivetkit/redis&quot;;
import Redis from &quot;ioredis&quot;;
import { registry } from &quot;./registry&quot;;

// Configure Redis connection
const redisClient = new Redis({
	db: Number.parseInt(process.env.REDIS_DB || &quot;0&quot;),
});

// Handle Redis connection events
redisClient.on(&quot;connect&quot;, () =&gt; {
	console.log(&quot;Connected to Redis&quot;);
});

redisClient.on(&quot;error&quot;, (err) =&gt; {
	console.error(&quot;Redis connection error:&quot;, err);
});

// Start server with Redis drivers using coordinate topology
registry.runServer({ driver: createRedisDriver() });

console.log(
	&quot;RivetKit server with Redis backend started on http://localhost:8088&quot;,
);
">
<input type="hidden" name="project[description]" value="generated by https://pkg.pr.new">
<input type="hidden" name="project[template]" value="node">
<input type="hidden" name="project[title]" value="example-redis">
</form>
<script>document.getElementById("mainForm").submit();</script>

</body></html>