Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
65636b4
feat: add Azure Managed Redis cluster support with explicit configura…
leggetter Aug 22, 2025
2b93c9d
refactor: remove unused routeDefinition type from router configuration
leggetter Aug 22, 2025
ee0cc01
feat: add Azure Managed Redis cluster support with explicit configura…
leggetter Aug 24, 2025
cccfa98
chore: move Redis troubleshooting guide for common connectivity issues
leggetter Aug 24, 2025
28856de
chore: implement NewForTest function for creating Redis client in tests
leggetter Aug 24, 2025
eade7aa
chore: add Redis cluster mode and TLS support to configuration
leggetter Aug 25, 2025
4a1b84f
refactor: clean up whitespace and improve error messages in Redis cli…
leggetter Aug 25, 2025
4c2eb1b
refactor: optimize IncrementConsecutiveFailureCount to use transactio…
leggetter Aug 25, 2025
6a0cdb8
refactor: improve atomicity in getInstallation function and add concu…
leggetter Aug 25, 2025
eefd519
chore(docs): README dependency clarification
leggetter Aug 27, 2025
cf0b42c
test: fix
alexluong Sep 15, 2025
7e9a81c
style: gofmt
alexluong Sep 16, 2025
c6ec493
refactor: rsmq using latest client
alexluong Sep 16, 2025
11edee9
chore: remove azure-specific reference
alexluong Sep 16, 2025
add19c5
test: set up test suite for local e2e redis cluster testing
alexluong Sep 19, 2025
84b7dad
chore: add --help to redis keys migration script
alexluong Sep 21, 2025
e194f10
chore: rename cmd/migrate -> cmd/migrationsql
alexluong Sep 21, 2025
1abe52b
fix: make internal redis client an interface to support regular and c…
alexluong Sep 21, 2025
e17277b
feat: cmd/migrateredis
alexluong Sep 22, 2025
bcb262d
feat: cmd/seed
alexluong Sep 22, 2025
271f783
chore: improve logger to print more error details
alexluong Sep 22, 2025
8b89b24
chore: small lint fix
alexluong Sep 22, 2025
4b7bef6
refactor: change redis key structure
alexluong Sep 22, 2025
aa863ee
test: improve internal/models test suite to avoid relying on redis ke…
alexluong Sep 22, 2025
b227f89
chore: READMEs
alexluong Sep 22, 2025
6cc4684
chore: move tenant redis key inside tenant folder
alexluong Sep 22, 2025
046e295
chore: small fixes migrateredis
alexluong Sep 22, 2025
c441f74
chore: improve plan 001_hash_tags
alexluong Sep 22, 2025
d8779b6
chore: azure script support custom id
alexluong Sep 22, 2025
88c7877
chore: support redis cluster
alexluong Sep 22, 2025
e4699d0
docs: config gen
alexluong Sep 22, 2025
74d7584
chore: avoid redis return nil nil
alexluong Sep 22, 2025
5033532
feat: outpost cli & redis migrator & startup logic (#498)
alexluong Oct 1, 2025
554308b
fix(portal): prevent inline SVG icons from inflating row height in ta…
leggetter Oct 1, 2025
f08bcac
chore: update README and scripts to require OUTPOST_AZURE_ID for depl…
leggetter Oct 1, 2025
59d0a22
refactor: use helper funcs
alexluong Oct 2, 2025
74d709d
chore: remove redis scripts & readme
alexluong Oct 2, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ REDIS_HOST="redis"
REDIS_PORT="6379"
REDIS_PASSWORD="password"
REDIS_DATABASE="0"
REDIS_TLS_ENABLED="false" # Enable TLS encryption (required for Azure Managed Redis)
REDIS_CLUSTER_ENABLED="false" # Enable cluster mode (required for Azure Managed Redis)

# ============================== Log Store ==============================

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ cmd/dev
.cursor/
.claude/
*.local.*
bin/
79 changes: 78 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,36 @@
TEST?=$$(go list ./...)

# Build targets
.PHONY: build
build:
@echo "Building all binaries..."
go build -o bin/outpost ./cmd/outpost
go build -o bin/outpost-server ./cmd/outpost-server
go build -o bin/outpost-migrate-redis ./cmd/outpost-migrate-redis
@echo "Binaries built in ./bin/"

build/goreleaser:
goreleaser release -f ./build/.goreleaser.yaml --snapshot --clean

build/outpost:
go build -o bin/outpost ./cmd/outpost

build/server:
go build -o bin/outpost-server ./cmd/outpost-server

build/migrate-redis:
go build -o bin/outpost-migrate-redis ./cmd/outpost-migrate-redis

install:
@echo "Installing binaries to GOPATH/bin..."
go install ./cmd/outpost
go install ./cmd/outpost-server
go install ./cmd/outpost-migrate-redis
@echo "Installation complete"

clean:
rm -f bin/outpost bin/outpost-server bin/outpost-migrate-redis

up:
make up/deps
make up/outpost
Expand Down Expand Up @@ -53,8 +84,42 @@ up/test:
down/test:
docker-compose -f build/test/compose.yml down --volumes

up/test/rediscluster:
@echo "Ensuring test network exists..."
@docker network create outpost-test_default 2>/dev/null || true
@UNAME_S=$$(uname -s); \
if [ "$$UNAME_S" = "Darwin" ]; then \
REDIS_IMAGE=neohq/redis-cluster:latest; \
echo "Detected macOS, using neohq/redis-cluster image..."; \
else \
REDIS_IMAGE=grokzen/redis-cluster:7.2.4; \
echo "Using grokzen/redis-cluster image..."; \
fi; \
REDIS_IMAGE=$$REDIS_IMAGE docker-compose -f build/test/redis-cluster-compose.yml up -d
@echo "Starting Redis cluster and test runner containers..."
@echo " - Redis cluster: 6 nodes (3 masters + 3 replicas)"
@echo " - Test runner: Alpine container with Go code mounted"
@echo ""
@echo "Waiting for cluster to initialize..."
@sleep 10
@echo "Checking Redis cluster status:"
@docker exec redis-cluster redis-cli -p 7000 cluster info | grep cluster_state || echo "Failed to check cluster status"
@echo ""
@echo "Test environment ready. Run: make test/e2e/rediscluster"

down/test/rediscluster:
@echo "Stopping Redis cluster test environment..."
@docker-compose -f build/test/redis-cluster-compose.yml down --volumes
@echo "Redis cluster test environment stopped."

test/setup:
bash scripts/test-setup-info.sh
@echo "To setup the test environment, run the following command:"
@echo "$$ make up/test"
@echo "$$ make up/azure"
@echo ""
@echo "Before running the tests, make sure to:"
@echo "$$ export TESTINFRA=1 TESTAZURE=1"
@echo ""

test:
go test $(TEST) $(TESTARGS)
Expand All @@ -65,6 +130,15 @@ test/unit:
test/integration:
go test $(TEST) $(TESTARGS) -run "Integration"

test/e2e/rediscluster:
@echo "Running Redis cluster e2e tests in Docker container..."
@if ! docker ps | grep -q test-runner; then \
echo "Error: test-runner container not running. Run 'make up/test/rediscluster' first."; \
exit 1; \
fi
@docker exec test-runner sh -c "cd /app && go test ./cmd/e2e -v -run TestRedisClusterBasicSuite"
@echo "Redis cluster e2e tests completed."

test/race:
TESTRACE=1 go test $(TEST) $(TESTARGS) -race

Expand All @@ -77,6 +151,9 @@ test/coverage/html:
docs/generate/config:
go run cmd/configdocsgen/main.go

redis/debug:
go run cmd/redis-debug/main.go $(ARGS)

network:
docker network create outpost

Expand Down
30 changes: 29 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ SDKs:

Outpost is a self-hosted and open-source infrastructure that enables event producers to add outbound webhooks and [Event Destinations](https://eventdestinations.org?ref=github-outpost) to their platform with support for destination types such as Webhooks, Hookdeck Event Gateway, Amazon EventBridge, AWS SQS, AWS S3, GCP Pub/Sub, RabbitMQ, and Kafka.

The Outpost runtime has minimal dependencies (Redis, PostgreSQL or Clickhouse, and one of the supported message queues), is 100% backward compatible with your existing webhooks implementation and is optimized for high-throughput, low-cost operation.
The Outpost runtime has minimal dependencies (Redis or Redis cluster, PostgreSQL, and one of the supported message queues), is 100% backward compatible with your existing webhooks implementation, and is optimized for high-throughput, low-cost operation.

Outpost is built and maintained by [Hookdeck](https://hookdeck.com?ref=github-outpost). It's written in Go and distributed as a binary and Docker container under the Apache-2.0 license.

Expand Down Expand Up @@ -118,6 +118,34 @@ cp .env.example .env

Update the `$API_KEY` value within the new `.env` file.

#### Redis Configuration

Outpost supports both standard Redis and cluster Redis configurations:

**Standard Redis** (default, for local development and single-node Redis):
```env
REDIS_HOST="redis"
REDIS_PORT="6379"
REDIS_TLS_ENABLED="false"
REDIS_CLUSTER_ENABLED="false"
```

**Redis Cluster** (for Redis Enterprise and managed Redis services):
```env
REDIS_HOST="your-redis-cluster.example.com"
REDIS_PORT="10000"
REDIS_TLS_ENABLED="true"
REDIS_CLUSTER_ENABLED="true"
```

For other cloud Redis services or self-hosted Redis clusters, set `REDIS_CLUSTER_ENABLED="true"` if using Redis clustering.

**Troubleshooting Redis connectivity**: Use the built-in diagnostic tool to test your Redis connection:
```sh
go run cmd/redis-debug/main.go your-redis-host 6379 password 0 [tls] [cluster]
```
See the [Redis Troubleshooting Guide](https://docs.outpost.hookdeck.com/references/troubleshooting-redis) for detailed guidance.

Start the Outpost dependencies and services:

```sh
Expand Down
74 changes: 72 additions & 2 deletions build/.goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@ before:

project_name: outpost

git:
# Ignore SDK tags when determining version
ignore_tags:
- 'sdks/*'

builds:
# Orchestrator binary
- id: outpost
ldflags:
- -s -w
Expand All @@ -16,7 +22,7 @@ builds:
binary: outpost
env:
- CGO_ENABLED=0
main: ./cmd/outpost/main.go
main: ./cmd/outpost
goos:
- linux
goarch:
Expand All @@ -29,7 +35,63 @@ builds:
binary: outpost
env:
- CGO_ENABLED=0
main: ./cmd/outpost/main.go
main: ./cmd/outpost
goos:
- linux
goarch:
- arm64

# Server binary
- id: outpost-server
ldflags:
- -s -w
- -X github.com/hookdeck/outpost/internal/version.version={{.Version}}
- -X github.com/hookdeck/outpost/internal/version.commit={{.FullCommit}}
binary: outpost-server
env:
- CGO_ENABLED=0
main: ./cmd/outpost-server
goos:
- linux
goarch:
- amd64
- id: outpost-server-arm64
ldflags:
- -s -w
- -X github.com/hookdeck/outpost/internal/version.version={{.Version}}
- -X github.com/hookdeck/outpost/internal/version.commit={{.FullCommit}}
binary: outpost-server
env:
- CGO_ENABLED=0
main: ./cmd/outpost-server
goos:
- linux
goarch:
- arm64

# Migration binary
- id: outpost-migrate-redis
ldflags:
- -s -w
- -X github.com/hookdeck/outpost/internal/version.version={{.Version}}
- -X github.com/hookdeck/outpost/internal/version.commit={{.FullCommit}}
binary: outpost-migrate-redis
env:
- CGO_ENABLED=0
main: ./cmd/outpost-migrate-redis
goos:
- linux
goarch:
- amd64
- id: outpost-migrate-redis-arm64
ldflags:
- -s -w
- -X github.com/hookdeck/outpost/internal/version.version={{.Version}}
- -X github.com/hookdeck/outpost/internal/version.commit={{.FullCommit}}
binary: outpost-migrate-redis
env:
- CGO_ENABLED=0
main: ./cmd/outpost-migrate-redis
goos:
- linux
goarch:
Expand Down Expand Up @@ -63,6 +125,10 @@ dockers:
dockerfile: ./build/Dockerfile.goreleaser
ids:
- outpost
- outpost-server
- outpost-migrate-redis
extra_files:
- build/entrypoint.sh
image_templates:
- "hookdeck/outpost:latest-amd64"
- "hookdeck/outpost:{{ .Tag }}-amd64"
Expand All @@ -80,6 +146,10 @@ dockers:
dockerfile: ./build/Dockerfile.goreleaser
ids:
- outpost-arm64
- outpost-server-arm64
- outpost-migrate-redis-arm64
extra_files:
- build/entrypoint.sh
image_templates:
- "hookdeck/outpost:latest-arm64"
- "hookdeck/outpost:{{ .Tag }}-arm64"
Expand Down
15 changes: 11 additions & 4 deletions build/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
# Stage 0
# Build the binary
# Build the binaries
FROM golang:1.23-alpine
WORKDIR /app
COPY . .

RUN go build -o ./bin/outpost ./cmd/outpost/main.go
# Build all binaries
RUN go build -o ./bin/outpost ./cmd/outpost/main.go && \
go build -o ./bin/outpost-server ./cmd/outpost-server/main.go && \
go build -o ./bin/outpost-migrate-redis ./cmd/outpost-migrate-redis/main.go

# Stage 1
# Copy binary to a new image
# Copy binaries to a new image
FROM scratch
COPY --from=0 /app/bin/outpost /bin/outpost
ENTRYPOINT ["/bin/outpost"]
COPY --from=0 /app/bin/outpost-server /bin/outpost-server
COPY --from=0 /app/bin/outpost-migrate-redis /bin/outpost-migrate-redis

# Default to running the server
ENTRYPOINT ["/bin/outpost", "serve"]
20 changes: 17 additions & 3 deletions build/Dockerfile.goreleaser
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
FROM gcr.io/distroless/base
COPY outpost outpost
ENTRYPOINT ["./outpost"]
FROM busybox:1.36-musl AS busybox

FROM gcr.io/distroless/base-debian12:nonroot

# Copy statically linked shell from busybox for entrypoint script
COPY --from=busybox /bin/sh /bin/sh

# Copy all binaries
COPY outpost /usr/local/bin/outpost
COPY outpost-server /usr/local/bin/outpost-server
COPY outpost-migrate-redis /usr/local/bin/outpost-migrate-redis

# Copy entrypoint script
COPY build/entrypoint.sh /usr/local/bin/entrypoint.sh

# Default entrypoint runs migrations and starts server
ENTRYPOINT ["/bin/sh", "/usr/local/bin/entrypoint.sh"]
2 changes: 1 addition & 1 deletion build/dev/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ FROM golang:1.23-alpine AS fetch
RUN go install github.com/air-verse/air@v1.61.1
WORKDIR /app
COPY . .
CMD ["air"]
ENTRYPOINT ["sh", "./build/dev/entrypoint.sh"]
10 changes: 10 additions & 0 deletions build/dev/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/sh
set -e

echo "- Running: go run ./cmd/outpost-migrate-redis init --current"

go run ./cmd/outpost-migrate-redis init --current

echo "- Running: air serve"

exec air serve
32 changes: 32 additions & 0 deletions build/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/bin/sh
set -e

# If any arguments are passed, delegate to outpost binary
# Examples: docker run hookdeck/outpost serve
# docker run hookdeck/outpost migrate plan
# docker run hookdeck/outpost --version
# docker run hookdeck/outpost --help
if [ "$#" -gt 0 ]; then
exec /usr/local/bin/outpost "$@"
fi

# Default behavior when no args: check migrations, then start server

echo "Checking database migrations..."
if ! /usr/local/bin/outpost migrate init --current --log-format=json; then
echo ""
echo "ERROR: Database migrations are pending."
echo "Please run migrations before starting the server:"
echo " docker run --rm -it hookdeck/outpost migrate apply"
echo ""
echo "For help with migration commands and configuration:"
echo " docker run --rm hookdeck/outpost migrate --help"
echo ""
echo "Learn more about Outpost migration workflow at:"
echo " https://outpost.hookdeck.com/docs/guides/migration"
echo ""
exit 1
fi

echo "Starting Outpost server..."
exec /usr/local/bin/outpost serve
Loading
Loading