DevPrep
  • Interview Prep
  • Projects
  • Resources
  • Pricing
  • About Us
Submit Question
DevPrep
  • Pricing
  • About Us
Submit Question

Practice

  • JavaScript
  • DSA
  • Machine Coding
  • System Design

Resources

  • Learning Tracks
  • Articles
  • Roadmaps
  • Compare Concepts
  • Glossary
  • Developer Tools
  • All Questions

Company

  • About
  • Pricing

Legal

  • Privacy Policy
  • Terms of Service
DevPrep

© 2026 DevPrep. All rights reserved.

← Back to Questions
HardMachine Coding

Implement Pub/Sub with Wildcard Topics

68 views

Problem Statement

Implement a pub/sub system where subscribers can use wildcards. Subscribe("user.*") should receive events from both "user.created" and "user.deleted".

Requirements

  • Subscribe(pattern): Subscribe with wildcard support (* matches any segment)
  • Publish(topic, message): Publish to all matching subscribers
  • Unsubscribe(id): Remove a subscription

Implementation

package pubsub

import (
    "strings"
    "sync"
    "sync/atomic"
)

type Message struct {
    Topic   string
    Payload interface{}
}

type Subscription struct {
    ID      uint64
    Pattern string
    Ch      chan Message
}

type PubSub struct {
    mu      sync.RWMutex
    subs    map[uint64]*Subscription
    counter uint64
}

func New() *PubSub {
    return &PubSub{
        subs: make(map[uint64]*Subscription),
    }
}

func (ps *PubSub) Subscribe(pattern string, bufSize int) *Subscription {
    id := atomic.AddUint64(&ps.counter, 1)
    
    sub := &Subscription{
        ID:      id,
        Pattern: pattern,
        Ch:      make(chan Message, bufSize),
    }
    
    ps.mu.Lock()
    ps.subs[id] = sub
    ps.mu.Unlock()
    
    return sub
}

func (ps *PubSub) Unsubscribe(id uint64) {
    ps.mu.Lock()
    if sub, ok := ps.subs[id]; ok {
        close(sub.Ch)
        delete(ps.subs, id)
    }
    ps.mu.Unlock()
}

func (ps *PubSub) Publish(topic string, payload interface{}) {
    msg := Message{Topic: topic, Payload: payload}
    
    ps.mu.RLock()
    defer ps.mu.RUnlock()
    
    for _, sub := range ps.subs {
        if matches(sub.Pattern, topic) {
            select {
            case sub.Ch <- msg:
            default:
                // Channel full, skip (or log warning)
            }
        }
    }
}

// matches checks if pattern matches topic
// * matches exactly one segment
// ** matches zero or more segments
func matches(pattern, topic string) bool {
    patternParts := strings.Split(pattern, ".")
    topicParts := strings.Split(topic, ".")
    
    return matchParts(patternParts, topicParts)
}

func matchParts(pattern, topic []string) bool {
    if len(pattern) == 0 && len(topic) == 0 {
        return true
    }
    
    if len(pattern) == 0 {
        return false
    }
    
    if pattern[0] == "**" {
        // ** matches zero or more segments
        if len(pattern) == 1 {
            return true // ** at end matches everything
        }
        // Try matching ** with different lengths
        for i := 0; i <= len(topic); i++ {
            if matchParts(pattern[1:], topic[i:]) {
                return true
            }
        }
        return false
    }
    
    if len(topic) == 0 {
        return false
    }
    
    if pattern[0] == "*" || pattern[0] == topic[0] {
        return matchParts(pattern[1:], topic[1:])
    }
    
    return false
}

func (ps *PubSub) Close() {
    ps.mu.Lock()
    defer ps.mu.Unlock()
    
    for _, sub := range ps.subs {
        close(sub.Ch)
    }
    ps.subs = make(map[uint64]*Subscription)
}

Usage

func main() {
    ps := pubsub.New()
    
    // Subscribe to all user events
    userSub := ps.Subscribe("user.*", 10)
    
    // Subscribe to all events
    allSub := ps.Subscribe("**", 10)
    
    // Consumer
    go func() {
        for msg := range userSub.Ch {
            fmt.Printf("User event: %s = %v\n", msg.Topic, msg.Payload)
        }
    }()
    
    // Publish events
    ps.Publish("user.created", map[string]string{"id": "123"})
    ps.Publish("user.deleted", map[string]string{"id": "456"})
    ps.Publish("order.created", map[string]string{"id": "789"})
    
    // user.* receives: user.created, user.deleted
    // ** receives: all three events
}

Sample Test Cases

Case 1
Input
subscribe="news.*", publish="news.sports"
Expected Output
Subscriber receives message
Case 2
Input
subscribe="news.sports", publish="news.*"
Expected Output
Exact subscriber receives wildcard publish
Case 3
Input
{"actions": [{"type": "subscribe", "pattern": "user.*", "bufSize": 10}, {"type": "publish", "topic": "user.created", "payload": "User 1"}, {"type": "publish", "topic": "user.deleted", "payload": "User 2"}, {"type": "publish", "topic": "order.created", "payload": "Order 1"}, {"type": "unsubscribe", "id": 1}], "expected_messages": {"1": ["user.created", "user.deleted"]}}
Expected Output
{"1": [{"Topic": "user.created", "Payload": "User 1"}, {"Topic": "user.deleted", "Payload": "User 2"}]}
Case 4
Input
{"actions": [{"type": "subscribe", "pattern": "user.*", "bufSize": 10}, {"type": "publish", "topic": "user.created", "payload": "User 1"}, {"type": "publish", "topic": "user.deleted", "payload": "User 2"}, {"type": "publish", "topic": "order.created", "payload": "Order 1"}], "expected_messages": {"user.*": [{"topic": "user.created", "payload": "User 1"}, {"topic": "user.deleted", "payload": "User 2"}]}}
Expected Output
true
Case 5
Input
{"actions": [{"type": "subscribe", "pattern": "**", "bufSize": 10}, {"type": "publish", "topic": "user.created", "payload": "User 1"}, {"type": "publish", "topic": "order.deleted", "payload": "Order 2"}], "expected_messages": {"**": [{"topic": "user.created", "payload": "User 1"}, {"topic": "order.deleted", "payload": "Order 2"}]}}
Expected Output
true
Case 6
Input
{"actions": [{"type": "subscribe", "pattern": "**", "bufSize": 10}, {"type": "publish", "topic": "user.created", "payload": "User 1"}, {"type": "publish", "topic": "order.created", "payload": "Order 1"}, {"type": "publish", "topic": "product.viewed", "payload": "Product A"}], "expected_messages": {"1": ["user.created", "order.created", "product.viewed"]}}
Expected Output
{"1": [{"Topic": "user.created", "Payload": "User 1"}, {"Topic": "order.created", "Payload": "Order 1"}, {"Topic": "product.viewed", "Payload": "Product A"}]}
Case 7
Input
{"actions": [{"type": "subscribe", "pattern": "a.b.c", "bufSize": 10}, {"type": "publish", "topic": "a.b.c", "payload": "Exact match"}, {"type": "publish", "topic": "a.b.d", "payload": "No match"}], "expected_messages": {"a.b.c": [{"topic": "a.b.c", "payload": "Exact match"}]}}
Expected Output
true
Case 8
Input
{"actions": [{"type": "subscribe", "pattern": "a.b.c", "bufSize": 10}, {"type": "subscribe", "pattern": "a.*.c", "bufSize": 10}, {"type": "subscribe", "pattern": "a.**", "bufSize": 10}, {"type": "publish", "topic": "a.b.c", "payload": "Message 1"}, {"type": "publish", "topic": "a.x.c", "payload": "Message 2"}, {"type": "publish", "topic": "a.y.z", "payload": "Message 3"}], "expected_messages": {"1": ["a.b.c"], "2": ["a.b.c", "a.x.c"], "3": ["a.b.c", "a.x.c", "a.y.z"]}}
Expected Output
{"1": [{"Topic": "a.b.c", "Payload": "Message 1"}], "2": [{"Topic": "a.b.c", "Payload": "Message 1"}, {"Topic": "a.x.c", "Payload": "Message 2"}], "3": [{"Topic": "a.b.c", "Payload": "Message 1"}, {"Topic": "a.x.c", "Payload": "Message 2"}, {"Topic": "a.y.z", "Payload": "Message 3"}]}

No solutions yet

Be the first to share a solution for this question.

Comments (0)

Sign in to leave a comment.

No comments yet. Be the first to comment.

Stats

Views
68
Likes
0
Solutions
0
Comments
0

Category

Backend Engineering

Languages

Go