func main() { flag.Usage = usage flag.Parse() urls := flag.Args() // Non-flag arguments are URLs to receive from if len(urls) == 0 { log.Println("No URL provided") usage() os.Exit(1) } messages := make(chan amqp.Message) // Channel for messages from goroutines to main() defer close(messages) var wait sync.WaitGroup // Used by main() to wait for all goroutines to end. wait.Add(len(urls)) // Wait for one goroutine per URL. _, prog := path.Split(os.Args[0]) container := electron.NewContainer(fmt.Sprintf("%v:%v", prog, os.Getpid())) connections := make(chan electron.Connection, len(urls)) // Connections to close on exit // Start a goroutine to for each URL to receive messages and send them to the messages channel. // main() receives and prints them. for _, urlStr := range urls { util.Debugf("Connecting to %s\n", urlStr) go func(urlStr string) { // Start the goroutine defer wait.Done() // Notify main() when this goroutine is done. url, err := amqp.ParseURL(urlStr) // Like net/url.Parse() but with AMQP defaults. util.ExitIf(err) // Open a new connection conn, err := net.Dial("tcp", url.Host) // Note net.URL.Host is actually "host:port" util.ExitIf(err) c, err := container.Connection(conn) connections <- c // Save connection so we can Close() when main() ends // Create a Receiver using the path of the URL as the source address r, err := c.Receiver(electron.Source(url.Path)) util.ExitIf(err) // Loop receiving messages and sending them to the main() goroutine for { rm, err := r.Receive() switch err { case electron.Closed: util.Debugf("closed %s", urlStr) return case nil: messages <- rm.Message default: log.Fatal(err) } } }(urlStr) } // All goroutines are started, we are receiving messages. fmt.Printf("Listening on %d connections\n", len(urls)) // print each message until the count is exceeded. for i := uint64(0); i < *count; i++ { m := <-messages util.Debugf("%s\n", util.FormatMessage(m)) } fmt.Printf("Received %d messages\n", *count) // Close all connections, this will interrupt goroutines blocked in Receiver.Receive() for i := 0; i < len(urls); i++ { c := <-connections util.Debugf("close %s", c) c.Close(nil) } wait.Wait() // Wait for all goroutines to finish. }
func main() { flag.Usage = usage flag.Parse() urls := flag.Args() // Non-flag arguments are URLs to receive from if len(urls) == 0 { log.Println("No URL provided") flag.Usage() os.Exit(1) } sentChan := make(chan electron.Outcome) // Channel to receive acknowledgements. var wait sync.WaitGroup wait.Add(len(urls)) // Wait for one goroutine per URL. _, prog := path.Split(os.Args[0]) container := electron.NewContainer(fmt.Sprintf("%v:%v", prog, os.Getpid())) connections := make(chan electron.Connection, len(urls)) // Connctions to close on exit // Start a goroutine for each URL to send messages. for _, urlStr := range urls { util.Debugf("Connecting to %v\n", urlStr) go func(urlStr string) { defer wait.Done() // Notify main() that this goroutine is done. url, err := amqp.ParseURL(urlStr) // Like net/url.Parse() but with AMQP defaults. util.ExitIf(err) // Open a new connection conn, err := net.Dial("tcp", url.Host) // Note net.URL.Host is actually "host:port" util.ExitIf(err) c, err := container.Connection(conn) util.ExitIf(err) connections <- c // Save connection so we can Close() when main() ends // Create a Sender using the path of the URL as the AMQP address s, err := c.Sender(electron.Target(url.Path)) util.ExitIf(err) // Loop sending messages. for i := int64(0); i < *count; i++ { m := amqp.NewMessage() body := fmt.Sprintf("%v-%v", url.Path, i) m.Marshal(body) s.SendAsync(m, sentChan, body) // Outcome will be sent to sentChan } }(urlStr) } // Wait for all the acknowledgements expect := int(*count) * len(urls) util.Debugf("Started senders, expect %v acknowledgements\n", expect) for i := 0; i < expect; i++ { out := <-sentChan // Outcome of async sends. if out.Error != nil { util.Debugf("acknowledgement[%v] %v error: %v\n", i, out.Value, out.Error) } else { util.Debugf("acknowledgement[%v] %v (%v)\n", i, out.Value, out.Status) } } fmt.Printf("Received all %v acknowledgements\n", expect) wait.Wait() // Wait for all goroutines to finish. close(connections) for c := range connections { // Close all connections if c != nil { c.Close(nil) } } }