예제 #1
0
/*
closeSconn closes a stompngo Connection.
*/
func closeSconn(n net.Conn, conn *stompngo.Connection) {
	ltag := tag + "-closesconn"

	// Standard example disconnect sequence
	e := sngecomm.CommonDisconnect(n, conn, exampid, ltag, ll)
	if e != nil {
		ll.Fatalf("%stag:%s connsess:%s disconnect_error error:%s\n",
			exampid, ltag, conn.Session(),
			e.Error()) // Handle this ......
	}
	return
}
예제 #2
0
// Send messages to a particular queue
func sender(conn *stompngo.Connection, qn, nmsgs int) {
	ltag := tag + "-sender"

	qns := fmt.Sprintf("%d", qn) // queue number
	d := sngecomm.Dest() + "." + qns
	ll.Printf("%stag:%s connsess:%s starts qn:%d nmsgs:%d d:%s\n",
		exampid, ltag, conn.Session(),
		qn, nmsgs, d)
	//
	wh := stompngo.Headers{"destination", d,
		"qnum", qns} // send Headers
	if senv.Persistent() {
		wh = wh.Add("persistent", "true")
	}
	//
	tmr := time.NewTimer(100 * time.Hour)
	// Send loop
	for i := 1; i <= nmsgs; i++ {
		si := fmt.Sprintf("%d", i)
		sh := append(wh, "msgnum", si)
		// Generate a message to send ...............
		ll.Printf("%stag:%s connsess:%s message qns:%s si:%s\n",
			exampid, ltag, conn.Session(),
			qns, si)
		e := conn.Send(sh, string(sngecomm.Partial()))
		if e != nil {
			ll.Fatalf("%stag:%s connsess:%s send_error qnum:%v error:%v",
				exampid, ltag, conn.Session(),
				qn, e.Error()) // Handle this ......
		}
		if i == nmsgs {
			break
		}
		if sw {
			runtime.Gosched() // yield for this example
			dt := time.Duration(sngecomm.ValueBetween(min, max, sf))
			ll.Printf("%stag:%s connsess:%s send_stagger dt:%v qns:%s\n",
				exampid, ltag, conn.Session(),
				dt, qns)
			tmr.Reset(dt)
			_ = <-tmr.C
		}
	}
	// Sending is done
	ll.Printf("%stag:%s connsess:%s sender_ends qn:%d nmsgs:%d\n",
		exampid, ltag, conn.Session(),
		qn, nmsgs)
	wgs.Done()
}
예제 #3
0
/*
runSender sends all messages to a specified queue.
*/
func runSender(conn *stompngo.Connection, qns string) {
	ltag := tag + "-runsender"

	d := sngecomm.Dest() + "." + qns
	id := stompngo.Uuid() // A unique sender id
	ll.Printf("%stag:%s connsess:%s start id:%s dest:%s\n",
		exampid, ltag, conn.Session(),
		id, d)
	wh := stompngo.Headers{"destination", d, "senderId", id,
		"qnum", qns} // basic send Headers
	if senv.Persistent() {
		wh = wh.Add("persistent", "true")
	}
	tmr := time.NewTimer(100 * time.Hour)
	nmsgs := senv.Nmsgs()
	for mc := 1; mc <= nmsgs; mc++ {
		sh := append(wh, "msgnum", fmt.Sprintf("%d", mc))
		// Generate a message to send ...............
		ll.Printf("%stag:%s  connsess:%s send id:%s qns:%s mc:%d\n",
			exampid, ltag, conn.Session(),
			id, qns, mc)
		e := conn.Send(sh, string(sngecomm.Partial()))
		if e != nil {
			ll.Fatalf("%stag:%s connsess:%s send_error qns:%v error:%v",
				exampid, ltag, conn.Session(),
				qns, e.Error()) // Handle this ......
		}
		if mc == nmsgs {
			break
		}
		if sw {
			dt := time.Duration(sngecomm.ValueBetween(min, max, sf))
			ll.Printf("%stag:%s connsess:%s send_stagger dt:%v qns:%s mc:%d\n",
				exampid, ltag, conn.Session(),
				dt, qns, mc)
			tmr.Reset(dt)
			_ = <-tmr.C
			runtime.Gosched()
		}
	}
	ll.Printf("%stag:%s connsess:%s end id:%s dest:%s\n",
		exampid, ltag, conn.Session(),
		id, d)
	//
	wgs.Done()
}
예제 #4
0
/*
receiverConnection starts individual receivers for this connection.
*/
func receiverConnection(conn *stompngo.Connection, cn, qpc int) {
	ltag := tag + "-receiverconnection"

	ll.Printf("%stag:%s connsess:%s starts cn:%d qpc:%d\n",
		exampid, ltag, conn.Session(),
		cn, qpc)

	// cn -> a connection number: 1..n
	// qpc -> destinations per connection
	// Ex:
	// 1, 2
	// 2, 2
	// 3, 2

	// This code runs *once* for each connection

	// These calcs are what causes a skip below.  It is a safety valve to keep
	// from starting one too many connections.
	cb := cn - 1       // this connection number, zero based
	q1 := qpc*cb + 1   // 1st queue number
	ql := q1 + qpc - 1 // last queue number
	if ql > sngecomm.Nqs() {
		ql = sngecomm.Nqs() // truncate last if over max destinations
	}

	var wgrconn sync.WaitGroup

	var skipped bool
	if q1 <= ql {
		ll.Printf("%stag:%s connsess:%s startq cn:%d q1:%d ql: %d\n",
			exampid, ltag, conn.Session(),
			cn, q1, ql)
		skipped = false
	} else {
		// Skips are possible, at least with the current calling code, see above
		ll.Printf("%stag:%s connsess:%s startskip cn:%d q1:%d ql: %d\n",
			exampid, ltag, conn.Session(),
			cn, q1, ql)
		skipped = true
	}

	for q := q1; q <= ql; q++ {
		wgrconn.Add(1)
		go runReceive(conn, q, &wgrconn)
	}
	wgrconn.Wait()
	//
	ll.Printf("%stag:%s connsess:%s ends cn:%d qpc:%d skipped:%t\n",
		exampid, ltag, conn.Session(),
		cn, qpc, skipped)
	wgr.Done()
}
예제 #5
0
// Common example disconnect logic
func CommonDisconnect(n net.Conn, conn *stompngo.Connection,
	exampid, tag string,
	l *log.Logger) error {

	// Disconnect from the Stomp server
	e := conn.Disconnect(stompngo.Headers{})
	if e != nil {
		return e
	}
	l.Printf("%stag:%s consess:%v common_disconnect_complete local_addr:%s remote_addr:%s\n",
		exampid, tag, conn.Session(),
		n.LocalAddr().String(), n.RemoteAddr().String())

	// Close the network connection
	e = n.Close()
	if e != nil {
		return e
	}

	// Parting messages
	l.Printf("%stag:%s consess:%v common_disconnect_network_close_complete\n",
		exampid, tag, conn.Session())
	l.Printf("%stag:%s consess:%v common_disconnect_ends\n",
		exampid, tag, conn.Session())

	//
	return nil
}
예제 #6
0
func sendMessages(conn *stompngo.Connection, qnum int, nc net.Conn) {
	ltag := tag + "-sendmessages"

	qns := fmt.Sprintf("%d", qnum) // queue number
	d := sngecomm.Dest() + "." + qns
	ll.Printf("%stag:%s connsess:%s start d:%s qnum:%d\n",
		exampid, ltag, conn.Session(),
		d, qnum)
	wh := stompngo.Headers{"destination", d,
		"qnum", qns} // send Headers
	if senv.Persistent() {
		wh = wh.Add("persistent", "true")
	}
	//
	tmr := time.NewTimer(100 * time.Hour)
	// Send messages
	for mc := 1; mc <= nmsgs; mc++ {
		mcs := fmt.Sprintf("%d", mc)
		sh := append(wh, "msgnum", mcs)
		// Generate a message to send ...............

		ll.Printf("%stag:%s connsess:%s message mc:%d qnum:%d\n",
			exampid, ltag, conn.Session(),
			mc, qnum)
		e := conn.Send(sh, string(sngecomm.Partial()))
		if e != nil {
			ll.Fatalf("%stag:%s connsess:%s send_error qnum:%v error:%v",
				exampid, ltag, conn.Session(),
				qnum, e.Error()) // Handle this ......
		}
		if mc == nmsgs {
			break
		}
		if sw {
			runtime.Gosched() // yield for this example
			dt := time.Duration(sngecomm.ValueBetween(min, max, sf))
			ll.Printf("%stag:%s connsess:%s send_stagger dt:%v qnum:%s mc:%d\n",
				exampid, ltag, conn.Session(),
				dt, qnum, mc)
			tmr.Reset(dt)
			_ = <-tmr.C
		}
	}
}
예제 #7
0
func recv(conn *stompngo.Connection, s int) {
	ltag := tag + "-recv"

	ll.Printf("%stag:%s connsess:%s receiver_starts s:%d\n",
		exampid, ltag, conn.Session(),
		s)

	// Setup Headers ...
	id := stompngo.Uuid() // Use package convenience function for unique ID
	d := sngecomm.Dest()
	ackMode = sngecomm.AckMode() // get ack mode

	pbc := sngecomm.Pbc() // Print byte count

	sc := sngecomm.HandleSubscribe(conn, d, id, ackMode)
	// Receive loop.
	mc := 0
	var md stompngo.MessageData
	for {
		select {
		case md = <-sc: // Read a messagedata struct, with a MESSAGE frame
		case md = <-conn.MessageData: // Read a messagedata struct, with a ERROR/RECEIPT frame
			// Frames RECEIPT or ERROR not expected here
			ll.Fatalf("%stag:%s connsess:%s bad_frame md:%v",
				exampid, ltag, conn.Session(),
				md) // Handle this ......
		}
		//
		mc++
		if md.Error != nil {
			ll.Fatalf("%stag:%s connsess:%s error_read error:%v",
				exampid, ltag, conn.Session(),
				md.Error) // Handle this ......
		}
		ll.Printf("%stag:%s connsess:%s received_message s:%d id:%s mc:%d\n",
			exampid, ltag, conn.Session(),
			s, id, mc)
		if pbc > 0 {
			maxlen := pbc
			if len(md.Message.Body) < maxlen {
				maxlen = len(md.Message.Body)
			}
			ss := string(md.Message.Body[0:maxlen])
			ll.Printf("%stag:%s connsess:%s payload body:%s\n",
				exampid, tag, conn.Session(),
				ss)
		}

		// time.Sleep(3 * time.Second) // A very arbitrary number
		// time.Sleep(500 * time.Millisecond) // A very arbitrary number
		runtime.Gosched()
		time.Sleep(1500 * time.Millisecond) // A very arbitrary number
		runtime.Gosched()
		if ackMode != "auto" {
			sngecomm.HandleAck(conn, md.Message.Headers, id)
			ll.Printf("%stag:%s connsess:%s ack_complete s:%d id:%s mc:%d\n",
				exampid, ltag, conn.Session(),
				s, id, mc)
		}
		runtime.Gosched()
	}
}
예제 #8
0
/*
runReceive receives all messages from a specified queue.
*/
func runReceive(conn *stompngo.Connection, q int, w *sync.WaitGroup) {
	ltag := tag + "-runreceive"

	qns := fmt.Sprintf("%d", q) // queue number
	id := stompngo.Uuid()       // A unique subscription ID
	d := sngecomm.Dest() + "." + qns

	ll.Printf("%stag:%s connsess:%s starts id:%s qns:%s d:%s\n",
		exampid, ltag, conn.Session(),
		id, qns, d)

	// Subscribe (use common helper)
	sc := sngecomm.HandleSubscribe(conn, d, id, sngecomm.AckMode())
	ll.Printf("%stag:%s connsess:%s subscribe_done id:%s qns:%s d:%s\n",
		exampid, ltag, conn.Session(),
		id, qns, d)

	//
	tmr := time.NewTimer(100 * time.Hour)

	pbc := sngecomm.Pbc() // Print byte count

	nmsgs := senv.Nmsgs()

	// Receive loop
	var md stompngo.MessageData
	for mc := 1; mc <= nmsgs; mc++ {
		ll.Printf("%stag:%s connsess:%s chanchek id:%s qns:%s lensc:%d capsc:%d\n",
			exampid, ltag, conn.Session(),
			id, qns, len(sc), cap(sc))
		select {
		case md = <-sc:
		case md = <-conn.MessageData:
			// Frames RECEIPT or ERROR not expected here
			ll.Fatalf("%stag:%s connsess:%s send_error qns:%v md:%v",
				exampid, ltag, conn.Session(),
				qns, md) // Handle this ......
		}

		if md.Error != nil {
			ll.Fatalf("%stag:%s connsess:%s receive_error qns:%v error:%v\n",
				exampid, ltag, conn.Session(),
				qns, md.Error)
		}

		// Process the inbound message .................
		ll.Printf("%stag:%s connsess:%s inbound id:%s qns:%s mc:%d\n",
			exampid, ltag, conn.Session(),
			id, qns, mc)
		// Sanity check the message Command, and the queue and message numbers
		mns := fmt.Sprintf("%d", mc) // string message number
		if md.Message.Command != stompngo.MESSAGE {
			ll.Fatalf("%stag:%s connsess:%s bad_frame qns:%s mc:%d md:%v\n",
				exampid, ltag, conn.Session(),
				qns, mc, md)
		}
		if !md.Message.Headers.ContainsKV("qnum", qns) || !md.Message.Headers.ContainsKV("msgnum", mns) {
			ll.Fatalf("%stag:%s connsess:%s dirty_message qns:%v msgnum:%v md:%v",
				exampid, tag, conn.Session(),
				qns, mns, md) // Handle this ......
		}

		sl := len(md.Message.Body)
		if pbc > 0 {
			sl = pbc
			if len(md.Message.Body) < sl {
				sl = len(md.Message.Body)
			}
		}

		ll.Printf("%stag:%s connsess:%s runReceive_recv_message id:%s body:%s qns:%s msgnum:%s\n",
			exampid, ltag, conn.Session(),
			id, string(md.Message.Body[0:sl]), qns,
			md.Message.Headers.Value("msgnum"))

		// Handle ACKs if needed
		if sngecomm.AckMode() != "auto" {
			ah := stompngo.Headers{}
			sngecomm.HandleAck(conn, ah, id)
		}
		if mc == nmsgs {
			break
		}
		if rw {
			dt := time.Duration(sngecomm.ValueBetween(min, max, rf))
			ll.Printf("%stag:%s connsess:%s recv_stagger dt:%v qns:%s mc:%d\n",
				exampid, ltag, conn.Session(),
				dt, qns, mc)
			tmr.Reset(dt)
			_ = <-tmr.C
			runtime.Gosched()
		}
	}
	// Unsubscribe
	sngecomm.HandleUnsubscribe(conn, d, id)

	ll.Printf("%stag:%s connsess:%s runRecieve_ends id:%s qns:%s\n",
		exampid, ltag, conn.Session(),
		id, qns)
	w.Done()
}
예제 #9
0
// Receive messages from a particular queue
func receiver(conn *stompngo.Connection, qn, nmsgs int) {
	ltag := tag + "-receiver"

	qns := fmt.Sprintf("%d", qn) // queue number
	ll.Printf("%stag:%s connsess:%s starts qns:%d nmsgs:%d\n",
		exampid, ltag, conn.Session(),
		qn, nmsgs)
	//
	qp := sngecomm.Dest() // queue name prefix
	q := qp + "." + qns
	ll.Printf("%stag:%s connsess:%s queue_info q:%s qn:%d nmsgs:%d\n",
		exampid, ltag, conn.Session(),
		q, qn, nmsgs)
	id := stompngo.Uuid() // A unique subscription ID
	sc := sngecomm.HandleSubscribe(conn, q, id, sngecomm.AckMode())
	ll.Printf("%stag:%s connsess:%s subscribe_complete\n",
		exampid, ltag, conn.Session())
	// Many receivers running under the same connection can cause
	// (wire read) performance issues.  This is *very* dependent on the broker
	// being used, specifically the broker's algorithm for putting messages on
	// the wire.
	// To alleviate those issues, this strategy insures that messages are
	// received from the wire as soon as possible.  Those messages are then
	// buffered internally for (possibly later) application processing.

	bs := -1 //
	if s := os.Getenv("STOMP_CONN2BUFFER"); s != "" {
		i, e := strconv.ParseInt(s, 10, 32)
		if nil != e {
			ll.Fatalf("%stag:%s connsess:%s CONN2BUFFER_conversion_error error:%v",
				exampid, ltag, conn.Session(),
				e.Error()) // Handle this ......

		} else {
			bs = int(i)
		}
	}
	if bs < 1 {
		bs = nmsgs
	}
	ll.Printf("%stag:%s connsess:%s mdbuffersize_qnum bs:%d qn:%d\n",
		exampid, ltag, conn.Session(),
		bs, qn)

	// Process all inputs async .......
	// var mc chan stompngo.MessageData
	mdc := make(chan stompngo.MessageData, bs)      // MessageData Buffer size
	dc := make(chan bool)                           // Receive processing done channel
	go receiveWorker(mdc, qns, nmsgs, dc, conn, id) // Start async processor
	for i := 1; i <= nmsgs; i++ {
		mdc <- <-sc // Receive message data as soon as possible, and internally queue it
	}
	ll.Printf("%stag:%s connsess:%s waitforWorkersBegin qns:%s\n",
		exampid, ltag, conn.Session(),
		qns)
	<-dc // Wait until receive processing is done for this queue
	ll.Printf("%stag:%s connsess:%s waitforWorkersEnd qns:%s\n",
		exampid, ltag, conn.Session(),
		qns)

	// Unsubscribe
	sngecomm.HandleUnsubscribe(conn, q, id)
	ll.Printf("%stag:%s connsess:%s unsubscribe_complete\n",
		exampid, ltag, conn.Session())

	// Receiving is done
	ll.Printf("%stag:%s connsess:%s ends qns:%s\n",
		exampid, ltag, conn.Session(),
		qns)
	wgr.Done()
}
예제 #10
0
// Asynchronously process all messages for a given subscription.
func receiveWorker(sc <-chan stompngo.MessageData, qns string, nmsgs int,
	qc chan<- bool, conn *stompngo.Connection, id string) {
	//
	ltag := tag + "-receiveWorker"

	tmr := time.NewTimer(100 * time.Hour)

	pbc := sngecomm.Pbc() // Print byte count

	// Receive loop
	var md stompngo.MessageData
	for i := 1; i <= nmsgs; i++ {

		select {
		case md = <-sc:
		case md = <-conn.MessageData:
			// Frames RECEIPT or ERROR not expected here
			ll.Fatalf("%stag:%s connsess:%s bad_frame qns:%v md:%v",
				exampid, ltag, conn.Session(),
				qns, md) // Handle this ......
		}
		if md.Error != nil {
			ll.Fatalf("%stag:%s connsess:%s recv_error qns:%v error:%v",
				exampid, ltag, conn.Session(),
				qns, md.Error) // Handle this ......
		}

		// Sanity check the queue and message numbers
		mns := fmt.Sprintf("%d", i) // message number
		if !md.Message.Headers.ContainsKV("qnum", qns) || !md.Message.Headers.ContainsKV("msgnum", mns) {
			ll.Fatalf("%stag:%s connsess:%s dirty_message qnum:%v msgnum:%v md:%v",
				exampid, ltag, conn.Session(),
				qns, mns, md) // Handle this ......
		}

		// Process the inbound message .................
		sl := len(md.Message.Body)
		if pbc > 0 {
			sl = pbc
			if len(md.Message.Body) < sl {
				sl = len(md.Message.Body)
			}
		}

		// Handle ACKs if needed
		if sngecomm.AckMode() != "auto" {
			ah := []string{}
			sngecomm.HandleAck(conn, ah, id)
		}
		ll.Printf("%stag:%s connsess:%s recv_message body:%s qns:%s msgnum:%s i:%v\n",
			exampid, ltag, conn.Session(),
			string(md.Message.Body[0:sl]),
			qns,
			md.Message.Headers.Value("msgnum"), i)
		if i == nmsgs {
			break
		}
		if rw {
			runtime.Gosched() // yield for this example
			dt := time.Duration(sngecomm.ValueBetween(min, max, rf))
			ll.Printf("%stag:%s connsess:%s recv_stagger dt:%v qns:%s\n",
				exampid, ltag, conn.Session(),
				dt, qns)
			tmr.Reset(dt)
			_ = <-tmr.C
		}
	}
	//
	qc <- true
}
예제 #11
0
func receiveMessages(conn *stompngo.Connection, qnum int, nc net.Conn) {
	ltag := tag + "-receivemessages"

	qns := fmt.Sprintf("%d", qnum) // queue number
	d := sngecomm.Dest() + "." + qns
	id := stompngo.Uuid() // A unique subscription ID

	ll.Printf("%stag:%s connsess:%s receiveMessages_start id:%s d:%s qnum:%d nmsgs:%d\n",
		exampid, ltag, conn.Session(),
		id, d, qnum, nmsgs)
	// Subscribe
	sc := sngecomm.HandleSubscribe(conn, d, id, sngecomm.AckMode())

	pbc := sngecomm.Pbc() // Print byte count

	//
	tmr := time.NewTimer(100 * time.Hour)
	var md stompngo.MessageData
	for mc := 1; mc <= nmsgs; mc++ {

		select {
		case md = <-sc:
		case md = <-conn.MessageData:
			// Frames RECEIPT or ERROR not expected here
			ll.Fatalf("%stag:%s connsess:%s send_error qns:%v md:%v",
				exampid, ltag, conn.Session(),
				qns, md) // Handle this ......
		}
		if md.Error != nil {
			ll.Fatalf("%stag:%s connsess:%s receive_error qns:%v error:%v\n",
				exampid, ltag, conn.Session(),
				qns, md.Error)
		}

		if md.Message.Command != stompngo.MESSAGE {
			ll.Fatalf("%stag:%s connsess:%s bad_frame qns:%s mc:%d md:%v\n",
				exampid, ltag, conn.Session(),
				qns, mc, md)
		}

		mcs := fmt.Sprintf("%d", mc) // message number
		if !md.Message.Headers.ContainsKV("qnum", qns) || !md.Message.Headers.ContainsKV("msgnum", mcs) {
			ll.Fatalf("%stag:%s connsess:%s dirty_message qns:%v msgnum:%v md:%v",
				exampid, tag, conn.Session(),
				qns, mcs, md) // Handle this ......
		}

		// Process the inbound message .................
		sl := len(md.Message.Body)
		if pbc > 0 {
			sl = pbc
			if len(md.Message.Body) < sl {
				sl = len(md.Message.Body)
			}
		}
		ll.Printf("%stag:%s connsess:%s receiveMessages_msg d:%s body:%s qnum:%d msgnum:%s\n",
			exampid, ltag, conn.Session(),
			d, string(md.Message.Body[0:sl]), qnum,
			md.Message.Headers.Value("msgnum"))
		if mc == nmsgs {
			break
		}
		// Handle ACKs if needed
		if sngecomm.AckMode() != "auto" {
			ah := []string{}
			sngecomm.HandleAck(conn, ah, id)
		}
		if mc == nmsgs {
			break
		}
		//
		if rw {
			runtime.Gosched() // yield for this example
			dt := time.Duration(sngecomm.ValueBetween(min, max, rf))
			ll.Printf("%stag:%s connsess:%s recv_stagger dt:%v qns:%s mc:%d\n",
				exampid, ltag, conn.Session(),
				dt, qns, mc)
			tmr.Reset(dt)
			_ = <-tmr.C
		}
	}
	ll.Printf("%stag:%s connsess:%s end d:%s qnum:%d nmsgs:%d\n",
		exampid, ltag, conn.Session(),
		d, qnum, nmsgs)

	// Unsubscribe
	sngecomm.HandleUnsubscribe(conn, d, id)
	//
}