SlideShare une entreprise Scribd logo
1  sur  35
Télécharger pour lire hors ligne
Ismael Celis
Networked pub/sub with Go, Ruby and ZMQ
bootic.net - Hosted e-commerce in South America
Store frontsTheme editor
Checkout
Dashboard
Image resizer API
… and more in the pipeline.
• analytics
• automated backups
• activity dashboard
• audit trail
Ancillary services
Also: Play with cool toys
Publisher 1
Publisher 2
Publisher 3
Events hub Events bus
pub/sub
Publisher 1
Publisher 2
Publisher 3
Events hub Events bus
pub/sub
JSON
UDP
msgpack ZMQ
Events hub Events bus
pub/sub
JSON
UDP
msgpack ZMQ
Stats
Backups
Logs
?
Websocket
pub / sub
Publisher 1
pub/sub
require 'socket'



socket = UDPSocket.new



message = {

time: Time.now.to_s,

type: 'pageview',

app: 'store_fronts',

data: {

account: 'acme',

user: 'Joe Bloggs',

domain: 'www.acme.com',

path: '/about/us',

ua: 'Mozilla/5.0 (Windows NT 6.2; Win64; x64)...'

}

}



json = ActiveSupport::JSON.encode(message)



socket.send(json, 0, 'events_hub_host', 5555)
Events hub
pub/sub
github.com/bootic/bootic_data_collector
func (daemon *Daemon) ReceiveDatagrams() {



for {

buffer := make([]byte, 1024)



daemon.Conn.ReadFromUDP(buffer)



event, err := data.DecodeJSON(buffer[:c])

daemon.Dispatch(event)



}



panic("should never have got myself into this.")

}
Events hub
pub/sub
github.com/bootic/bootic_data_collector
// Start up UDP daemon
daemon, err := udp.NewDaemon(udpHost)



// Start up PUB ZMQ client

zmqObserver := fanout.NewZmq(zmqAddress)



// Push incoming UDP events down ZMQ pub/sub socket

daemon.Subscribe(zmqObserver.Notifier)
Events hub
pub/sub
github.com/bootic/bootic_data_collector
daemon, err := udp.NewDaemon(udpHost)
Events hub
pub/sub
github.com/bootic/bootic_data_collector
type Daemon struct {

Conn *net.UDPConn

observers map[string][]data.EventsChannel

}



func NewDaemon(udpHostAndPort string) (daemon *Daemon, err error) {

conn, err := createUDPListener(udpHostAndPort)



if err != nil {

return

}



daemon = &Daemon{

Conn: conn,

observers: make(map[string][]data.EventsChannel),

}



go daemon.ReceiveDatagrams()



return

}
Events hub
pub/sub
github.com/bootic/bootic_data_collector
go daemon.ReceiveDatagrams()
Events hub
pub/sub
github.com/bootic/bootic_data_collector


daemon, err := udp.NewDaemon(udpHost)



// Start up PUB ZMQ client

zmqObserver := fanout.NewZmq(zmqAddress)



// Push incoming UDP events down ZMQ pub/sub socket

daemon.Subscribe(zmqObserver.Notifier)
Events hub
pub/sub
github.com/bootic/bootic_data_collector
daemon.Subscribe(zmqObserver.Notifier)
Events hub
pub/sub
github.com/bootic/bootic_data_collector
// Start up UDP daemon

daemon, err := udp.NewDaemon(udpHost)





// Setup Websockets server

wshub := ws.HandleWebsocketsHub("/ws")



// Push incoming UDP messages to multiple listeners

daemon.Subscribe(wshub.Notifier)



// Start up PUB ZMQ client

zmqObserver := fanout.NewZmq(zmqAddress)



// Push incoming UDP events down ZMQ pub/sub socket

daemon.Subscribe(zmqObserver.Notifier)



log.Fatal("HTTP server error: ", http.ListenAndServe(wsHost, nil))
pub / sub
pageviews
tracker
Events hub
1px tracking .gif JSON / UDP
github.com/bootic/bootic_pageviews
Events hub
Redis
pub sub
aggregator HTTP API
internets
“pageview”
Stats
aggregates
pub/sub
// Setup ZMQ subscriber

daemon, _ := booticzmq.NewZMQSubscriber(zmqAddress)



// Setup Redis tracker

tracker, err := redis_stats.NewTracker(redisAddress)





// Redis subscribes to these events

daemon.SubscribeToType(tracker.Notifier, "pageview")
github.com/bootic/bootic_stats_aggregates
Stats
aggregates
pub/sub
github.com/bootic/bootic_stats_aggregates
year := now.Year()

month := now.Month()

day := now.Day()

hour := now.Hour()



go func () {



// increment current month in year: “track:acme/pageview/2013”

yearKey := fmt.Sprintf("track:%s/%s/%s", account, evtType, year)

self.Conn.HIncrBy(yearKey, month, 1)



// increment current day in month: “track:acme/pageview/2013/12”

monthKey := fmt.Sprintf("track:%s/%s/%s/%s", key, evtType, year, month)

self.Conn.HIncrBy(monthKey, day, 1)



// increment current hour in day: “track:acme/pageview/2013/12/16”

dayKey := fmt.Sprintf("track:%s/%s/%s/%s/%s", key, evtType, year, month, day)

self.Conn.HIncrBy(dayKey, hour, 1)



}()
Stats
aggregates
pub/sub
github.com/bootic/bootic_stats_aggregates
GET /api/stats/track/acme/pageview/2013/12/16
{

"account": "acme",

"event": "pageview",

"year": "2013",

"month": "12",

"day": "16",

"data": {

"0": 2693,

"1": 1215,

"2": 341,

"3": 176,

"4": 80,

"5": 89,

"6": 333,

"7": 779,

"8": 1506,

"9": 2553,

"10": 3734

}

}

Stats
aggregates
pub/sub
github.com/bootic/bootic_stats_aggregates
Git backups
pub/sub
github.com/bootic/bootic_themes_backup
Events hub
pub sub
Git backups
Themes API
“theme”
Git
Git
git clone tufte:/home/git/git_themes/acme
Git backups
pub/sub
doneChan := make(chan string)

bufferChan := make(chan int, 20)



stores := make(map[string]*ThemeStore)



for {

select {

case event := <-writer.Notifier:

account := event.Get("account")



store := stores[account]

// Register store and start delayed writing 

// if not already registered

if store == nil {

store = NewThemeStore(account)

stores[account] = store

go store.DelayedWrite(bufferChan, doneChan)

}



case account := <-doneChan:

// A store is done writing. 

// Un-register it so it can be registered again.

delete(stores, account)

}

}
github.com/bootic/bootic_themes_backup
Git backups
pub/sub
github.com/bootic/bootic_themes_backup
go store.DelayedWrite(bufferChan, doneChan)
doneChan := make(chan string)

bufferChan := make(chan int, 20)



…
Git backups
pub/sub
github.com/bootic/bootic_themes_backup
func (store *ThemeStore) DelayedWrite(bufferChan chan int, doneChan chan string) {



time.Sleep(10)



// Start work. This will block if buffer is full.

bufferChan <- 1



store.Backup()



// Done. Free space in the buffer

<-bufferChan



doneChan <- store.Account

}()

}
doneChan := make(chan string)

bufferChan := make(chan int, 20)



…
The future
The future
• Searchable events history
• Per-account secure websocket
• More stats!
• Webhooks
Ismael Celis @ismasan
bit.ly/1fYmUff
Blog post
bit.ly/1fYmUff
Ismael Celis @ismasan
bootic/bootic_data_collector
bootic/bootic_pageviews
bootic/bootic_stats_aggregates
bootic/bootic_themes_backup
Githubs
bootic/bootic_stathat
Blog post
Ismael Celis @ismasan

Contenu connexe

En vedette

CYNH Holiday Slideshow with music
CYNH Holiday Slideshow with musicCYNH Holiday Slideshow with music
CYNH Holiday Slideshow with musicbkessling
 
Tribuna Celíaca nº 20
Tribuna Celíaca nº 20Tribuna Celíaca nº 20
Tribuna Celíaca nº 20celiacscat
 
Zmq in context of openstack
Zmq in context of openstackZmq in context of openstack
Zmq in context of openstackYatin Kumbhare
 
Odontologia equina carolina
Odontologia equina carolinaOdontologia equina carolina
Odontologia equina carolinaluirpo
 
Introduction to ZeroMQ - eSpace TechTalk
Introduction to ZeroMQ - eSpace TechTalkIntroduction to ZeroMQ - eSpace TechTalk
Introduction to ZeroMQ - eSpace TechTalkMahmoud Said
 
Zeromq anatomy & jeromq
Zeromq anatomy & jeromqZeromq anatomy & jeromq
Zeromq anatomy & jeromqDongmin Yu
 
StoreDot Takes Over The World
StoreDot Takes Over The WorldStoreDot Takes Over The World
StoreDot Takes Over The WorldBlonde 2.0
 
Software Architecture over ZeroMQ
Software Architecture over ZeroMQSoftware Architecture over ZeroMQ
Software Architecture over ZeroMQpieterh
 
ZeroMQ: Super Sockets - by J2 Labs
ZeroMQ: Super Sockets - by J2 LabsZeroMQ: Super Sockets - by J2 Labs
ZeroMQ: Super Sockets - by J2 LabsJames Dennis
 
Script and practice for the speaking activity level 0
Script and practice for the speaking activity level 0Script and practice for the speaking activity level 0
Script and practice for the speaking activity level 0Karen Villalba
 
Build reliable, traceable, distributed systems with ZeroMQ
Build reliable, traceable, distributed systems with ZeroMQBuild reliable, traceable, distributed systems with ZeroMQ
Build reliable, traceable, distributed systems with ZeroMQRobin Xiao
 
Course 7-Unit 10: Superlative adjectives.
Course 7-Unit 10: Superlative adjectives.Course 7-Unit 10: Superlative adjectives.
Course 7-Unit 10: Superlative adjectives.Martin Caicedo
 
Europycon2011: Implementing distributed application using ZeroMQ
Europycon2011: Implementing distributed application using ZeroMQEuropycon2011: Implementing distributed application using ZeroMQ
Europycon2011: Implementing distributed application using ZeroMQfcrippa
 
ZeroMQ Is The Answer
ZeroMQ Is The AnswerZeroMQ Is The Answer
ZeroMQ Is The AnswerIan Barber
 

En vedette (18)

CYNH Holiday Slideshow with music
CYNH Holiday Slideshow with musicCYNH Holiday Slideshow with music
CYNH Holiday Slideshow with music
 
Tema 3
Tema 3Tema 3
Tema 3
 
Multiportal 130925112602-phpapp01
Multiportal 130925112602-phpapp01Multiportal 130925112602-phpapp01
Multiportal 130925112602-phpapp01
 
Tribuna Celíaca nº 20
Tribuna Celíaca nº 20Tribuna Celíaca nº 20
Tribuna Celíaca nº 20
 
Zmq in context of openstack
Zmq in context of openstackZmq in context of openstack
Zmq in context of openstack
 
Odontologia equina carolina
Odontologia equina carolinaOdontologia equina carolina
Odontologia equina carolina
 
Introduction to ZeroMQ - eSpace TechTalk
Introduction to ZeroMQ - eSpace TechTalkIntroduction to ZeroMQ - eSpace TechTalk
Introduction to ZeroMQ - eSpace TechTalk
 
Zeromq anatomy & jeromq
Zeromq anatomy & jeromqZeromq anatomy & jeromq
Zeromq anatomy & jeromq
 
StoreDot Takes Over The World
StoreDot Takes Over The WorldStoreDot Takes Over The World
StoreDot Takes Over The World
 
Software Architecture over ZeroMQ
Software Architecture over ZeroMQSoftware Architecture over ZeroMQ
Software Architecture over ZeroMQ
 
ZeroMQ: Super Sockets - by J2 Labs
ZeroMQ: Super Sockets - by J2 LabsZeroMQ: Super Sockets - by J2 Labs
ZeroMQ: Super Sockets - by J2 Labs
 
Script and practice for the speaking activity level 0
Script and practice for the speaking activity level 0Script and practice for the speaking activity level 0
Script and practice for the speaking activity level 0
 
Build reliable, traceable, distributed systems with ZeroMQ
Build reliable, traceable, distributed systems with ZeroMQBuild reliable, traceable, distributed systems with ZeroMQ
Build reliable, traceable, distributed systems with ZeroMQ
 
Leis de Newton
Leis de NewtonLeis de Newton
Leis de Newton
 
Course 7-Unit 10: Superlative adjectives.
Course 7-Unit 10: Superlative adjectives.Course 7-Unit 10: Superlative adjectives.
Course 7-Unit 10: Superlative adjectives.
 
Europycon2011: Implementing distributed application using ZeroMQ
Europycon2011: Implementing distributed application using ZeroMQEuropycon2011: Implementing distributed application using ZeroMQ
Europycon2011: Implementing distributed application using ZeroMQ
 
Mejora de la Competitividad
Mejora de la CompetitividadMejora de la Competitividad
Mejora de la Competitividad
 
ZeroMQ Is The Answer
ZeroMQ Is The AnswerZeroMQ Is The Answer
ZeroMQ Is The Answer
 

Dernier

AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024The Digital Insurer
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...apidays
 
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfOrbitshub
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businesspanagenda
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...apidays
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodJuan lago vázquez
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherRemote DBA Services
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Jeffrey Haguewood
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesrafiqahmad00786416
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FMESafe Software
 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdfSandro Moreira
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...DianaGray10
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Angeliki Cooney
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamUiPathCommunity
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...apidays
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingEdi Saputra
 

Dernier (20)

AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 

Networked pub/sub with UDP, Go, Ruby and ZMQ