A high-performance ranking and recommendation engine for the AroundU job marketplace, built in Rust and inspired by X's (Twitter's) open-source candidate-pipeline architecture.
The engine ranks jobs for workers and recommends workers for clients using a multi-stage pipeline: Source → Hydrate → Filter → Score → Select → Side-Effect — the same pattern X uses to power its home timeline.
┌─────────────────────────────────────────────────────────────────────┐
│ AroundU Ranking Engine │
│ │
│ ┌─────────────┐ ┌──────────────────────────────────────────────┐ │
│ │ gRPC API │ │ Candidate Pipeline (lib) │ │
│ │ (tonic) │ │ │ │
│ │ │ │ Source → QueryHydrator → Hydrator → Filter │ │
│ │ WorkerFeed │──▶│ → Scorer → Selector → SideEffect │ │
│ │ WorkerRecs │ │ │ │
│ │ Interaction │ │ Generic trait-based, fully async │ │
│ └─────────────┘ └──────────────────────────────────────────────┘ │
│ │ │ │
│ ┌────▼────┐ ┌─────▼─────┐ │
│ │ Proto │ │ PostgreSQL │ │
│ │ Schema │ │ (shared) │ │
│ └─────────┘ └───────────┘ │
└─────────────────────────────────────────────────────────────────────┘
aroundu-ranking-engine/
├── Cargo.toml # Workspace root
├── config.toml # Default configuration (scoring weights, DB, Redis)
├── proto/
│ └── ranking.proto # gRPC service definition (3 RPCs)
├── candidate-pipeline/ # Generic pipeline library (ported from X's algorithm)
│ └── src/
│ ├── lib.rs
│ ├── pipeline.rs # 10-stage pipeline orchestrator
│ ├── source.rs # Source<Q, C> trait
│ ├── hydrator.rs # Hydrator<Q, C> trait
│ ├── query_hydrator.rs # QueryHydrator<Q> trait
│ ├── filter.rs # Filter<Q, C> trait
│ ├── scorer.rs # Scorer<Q, C> trait
│ ├── selector.rs # Selector<Q, C> trait
│ ├── side_effect.rs # SideEffect<Q, C> trait
│ └── util.rs
├── ranking-server/ # gRPC server binary
│ ├── build.rs # tonic-build proto compilation
│ └── src/
│ ├── main.rs # Entry point (tokio, tonic server)
│ ├── server.rs # RankingService gRPC implementation
│ ├── config.rs # TOML + env var configuration
│ ├── db.rs # PostgreSQL connection pool (sqlx)
│ ├── models/ # Domain models (JobCandidate, WorkerCandidate)
│ ├── sources/ # JobSource, WorkerSource (PostgreSQL geo-queries)
│ ├── hydrators/ # Skill, metrics, collaboration hydrators
│ ├── filters/ # Status, distance, already-bid filters
│ ├── scorers/ # Weighted multi-signal scoring
│ ├── selectors/ # TopK selection with tie-breaking
│ ├── side_effects/ # Impression logging
│ ├── pipelines/ # Pipeline wiring (WorkerFeed, WorkerRecommendation)
│ └── proto/ # Generated protobuf code
└── docker/
└── Dockerfile # Multi-stage build (rust:1.78 → debian:bookworm-slim)
The engine exposes three RPCs on port 50052:
| RPC | Description |
|---|---|
GetWorkerFeed |
Returns ranked jobs for a worker based on skills, distance, budget, recency, urgency, and popularity |
GetWorkerRecommendations |
Returns ranked workers recommended for a specific job |
RecordInteraction |
Records view/bid events for future scoring signals |
service RankingService {
rpc GetWorkerFeed(WorkerFeedRequest) returns (WorkerFeedResponse);
rpc GetWorkerRecommendations(WorkerRecommendationRequest) returns (WorkerRecommendationResponse);
rpc RecordInteraction(RecordInteractionRequest) returns (RecordInteractionResponse);
}| Signal | Weight | Description |
|---|---|---|
| Skill Match | 0.35 | Jaccard similarity between worker and job skills |
| Distance | 0.25 | Inverse distance score (closer = higher) |
| Budget | 0.20 | Price alignment with market median |
| Recency | 0.10 | Exponential decay over 72 hours |
| Urgency | 0.05 | Bonus for URGENT/SAME_DAY jobs |
| Popularity | 0.05 | View and bid engagement signals |
| Signal | Weight | Description |
|---|---|---|
| Skill Match | 0.30 | Required skills coverage |
| Rating | 0.25 | Normalized average rating (0-5 → 0-1) |
| Distance | 0.20 | Inverse distance from job location |
| Completion Rate | 0.15 | Historical job completion rate |
| Response Rate | 0.10 | Bid response timeliness |
| Repeat Bonus | 0.10 | Extra score for prior collaborations |
All weights are configurable via config.toml or environment variables (prefix RANKING__).
Each request flows through the full candidate pipeline:
- Query Hydrators — Enrich the query (e.g., fetch worker's skill IDs)
- Sources — Fetch candidates from PostgreSQL (geo-bounded queries)
- Hydrators — Batch-enrich candidates (skills, metrics, collaboration history)
- Filters — Remove ineligible candidates (wrong status, too far, already bid)
- Scorers — Compute weighted multi-signal scores
- Selector — TopK selection with tie-breaking (distance, recency/rating)
- Side Effects — Fire-and-forget impression logging
- Rust 1.78+ (stable)
- protoc (Protocol Buffers compiler) —
brew install protobuf - PostgreSQL — Shared with the AroundU Java backend
- Redis (optional, for future caching)
# Clone
git clone https://github.com/AroundUPlatform/aroundu-ranking-engine.git
cd aroundu-ranking-engine
# Build
cargo build --release
# Run (ensure PostgreSQL is available)
export RANKING__DATABASE__URL="postgresql://user:pass@localhost:5432/aroundu"
cargo run --release
# Or with config.toml
cp config.toml /etc/ranking-engine/config.toml
cargo run --releaseConfiguration is loaded from config.toml with environment variable overrides (prefix RANKING__, double underscore for nesting):
[server]
grpc_port = 50052
max_concurrent_requests = 100
[database]
url = "postgresql://postgres:postgres@localhost:5432/aroundu"
max_connections = 10
[redis]
url = "redis://localhost:6379"
cache_ttl_seconds = 300
[scoring.worker_feed]
skill = 0.35
distance = 0.25
budget = 0.20
recency = 0.10
urgency = 0.05
popularity = 0.05
[scoring.worker_recommendation]
skill = 0.30
rating = 0.25
distance = 0.20
completion = 0.15
response = 0.10
repeat_bonus = 0.10# Build
docker build -f docker/Dockerfile -t aroundu-ranking-engine .
# Run
docker run -p 50052:50052 \
-e RANKING__DATABASE__URL=postgresql://user:pass@host:5432/aroundu \
aroundu-ranking-engineThe Java backend communicates with this engine via gRPC. The proto file includes Java package options:
option java_multiple_files = true;
option java_package = "com.aroundu.ranking.v1";The backend calls GetWorkerFeed for the /jobs/worker/{id}/feed endpoint and GetWorkerRecommendations for client-facing worker suggestions, with automatic fallback to the existing local implementation if the ranking engine is unavailable.
| Component | Technology |
|---|---|
| Language | Rust (Edition 2024) |
| gRPC | tonic 0.12 + prost 0.13 |
| Database | sqlx 0.8 (PostgreSQL) |
| Async Runtime | tokio (multi-threaded) |
| Config | config crate + TOML |
| Observability | tracing + tracing-subscriber (JSON) |
| Health Check | tonic-health |
MIT