Skip to content


Repository files navigation

CircleCI SCAMP Go Lang Edition

The scamp package provides all the facilities necessary for participating in a SCAMP environment:

  • Parsing the discovery cache and building a directory of available services
  • Parsing packets streams
  • Parsing and verifying messages

// inventory map[string]int

// severity = expectedInventory.checkIsBad(inventory)

// if severity < happy { // incident = newIncident() // inventoryDiff = diff(inventoryPrev, inventoryNow) // incident.remember(inventoryPrev) // } else { // incident.close() // }


Remote services are invoked by first establishing a Connection (TLS under the hood). This Connection can then be used to spawn Sessions which send a Request and block until a Reply is provided.


func main() {

	conn := new(scamp.Connection)
	err := conn.Connect("")
	defer conn.Close()

	if err != nil {
		scamp.Error.Printf("could not connect! `%s`\n", err)

	request := scamp.Request{
		Action:         "helloworld.hello",
		envelopeFormat: scamp.ENVELOPE_JSON,
		Version:        1,
	reply, err := conn.RecvReply()
	if err != nil {
		scamp.Error.Printf("error receving reply: `%s`", err)
	scamp.Info.Printf("got reply: `%s`", reply)

Running the test suite

export GOPATH=$PWD go test scamp


export GOPATH=$PWD
godoc -http=:6060
# open http://localhost:6060/


Need to run two components without discovery? Generate a fake discovery cache using the cli

go run cli/scamp.go -announcepath=fixtures/sample_service_spec -keypath=fixtures/sample.key -certpath=fixtures/sample.crt

and then copy this text to /tmp/discovery.cache in your gt-dispatcher.



  • Setup Go project
  • TLS session setup
  • cert verification
  • Parse packet
  • Generate packet
  • Generate request
    • Generate request header JSON
  • Parse reply
  • Parse request
    • Route to action based on header JSON
  • Generate reply
  • Verify TLS certificate with /etc/authorized_services
  • Manage connection msgno
  • Parse service cache
  • Choose service listen port randomly from within configured range
  • Announce service
    • Copy Service details to ServiceProxy (which can serialize)
    • Write ServiceProxy to UDP multicast
    • Investigate merging Service/ServiceProxy
  • Route RPC based on service cache
  • Use go logging library
  • AuthZ service support
    • Ticket parsing
    • Ticket verification
    • Put it to use?
  • Chunk body to 128k
  • Reconnect logic
  • What to do if connection goes down during Session exchange?
  • Time out connections
  • ACK packets
    • Modify when sent based on message token
  • Nuke session code and move to client with bidirectional packet streams
  • Audit how connections are freed from demux lookup structure
  • RequestId should be generated on Message allocation, not Message send

Important Restructuring

  • Stream messages bodies
    • Session stream interface? Reader/Writer for bytes? Benefit: integration with patterns/helpers in (io lib)[]
  • Unify concepts of Request/Reply with Message and move that distinction to the direction of the Session
    • Rewrite Request/Reply code to reuse session Reader/Writer under the hood

Rad/Cool Ideas

  • Ragel state machine specification to generate go code


  • Fix bug where sending envelope type JSON fails silently (should at least emit 'unknown type' to STDERR)
  • Fix bug where header "type": "request" fails silently (should at least emit 'unknown type' to STDERR)
  • Fix reference to documentation message_id which should read request_id
  • Move to interface design. Message parts which implement Packet so we can specialize Header vs Data which have different bodies from different data types.