func publish(bucket *ratelimit.Bucket) { conn, err := amqp.Dial("amqp://*****:*****@localhost:5672/") failOnError(err, "Failed to connect to RabbitMQ") defer conn.Close() ch, err := conn.Channel() failOnError(err, "Failed to open a channel") defer ch.Close() q, err := ch.QueueDeclare( "hello", // name false, // durable false, // delete when unused false, // exclusive false, // no-wait nil, // arguments ) failOnError(err, "Failed to declare a queue") for { bucket.Wait(1) body := "hello" err = ch.Publish( "", // exchange q.Name, // routing key false, // mandatory false, // immediate amqp.Publishing{ ContentType: "text/plain", Body: []byte(body), }) failOnError(err, "Failed to publish a message") } }
func makeRateLimitFunc(sessionRateLimit, globalRateLimit *ratelimit.Bucket) func(int64) { // This may be a case of super duper premature optimization... We build an // optimized function to do the rate limiting here based on what we need // to do and then use it in the loop. if sessionRateLimit == nil && globalRateLimit == nil { // No limiting needed. We could equally well return a func(int64){} and // not do a nil check were we use it, but I think the nil check there // makes it clear that there will be no limiting if none is // configured... return nil } if sessionRateLimit == nil { // We only have a global limiter return func(bytes int64) { globalRateLimit.Wait(bytes) } } if globalRateLimit == nil { // We only have a session limiter return func(bytes int64) { sessionRateLimit.Wait(bytes) } } // We have both. Queue the bytes on both the global and session specific // rate limiters. Wait for both in parallell, so that the actual send // happens when both conditions are satisfied. In practice this just means // wait the longer of the two times. return func(bytes int64) { t0 := sessionRateLimit.Take(bytes) t1 := globalRateLimit.Take(bytes) if t0 > t1 { time.Sleep(t0) } else { time.Sleep(t1) } } }