SlideShare une entreprise Scribd logo
1  sur  47
Télécharger pour lire hors ligne
 
Adding Context to
Waldemar Quevedo /
GopherFest 2017
@wallyqs
1 . 1
Waldemar Quevedo /
So!ware Developer at
Development of the Apcera Platform
NATS client maintainer (Ruby, Python)
Using NATS since 2012
Speaking at GopherCon 2017 :D
ABOUT
@wallyqs
Apcera
2 . 1
ABOUT THIS TALK
Quick intro to the NATS project
What is Context? When to use it?
How we added Context support to the NATS client
What can we do with Context and NATS together
3 . 1
Short intro to the NATS project…
! ! !
(for context)
4 . 1
WHAT IS NATS?
High Performance Messaging System
Open Source, MIT License
First written in in 2010
Rewritten in in 2012
Used in production for years at
CloudFoundry, Apcera Platform
On Github:
Website:
Ruby
Go
https://github.com/nats-io
http://nats.io/
5 . 1
WHAT IS NATS?
Fast, Simple & Resilient
Minimal feature set
Pure PubSub (no message persistence*)
at-most-once delivery
TCP/IP based under a basic plain text protocol
(Payload is opaque to protocol)
 * see project for at-least once deliveryNATS Streaming
6 . 1
WHAT IS NATS USEFUL FOR?
Useful to build control planes for microservices
Supports <1:1, 1:N> types of communication
Low Latency Request/Response
Load balancing via Distribution Queues
Great Throughput
Above 10M messages per/sec for small payloads
Max payload is 1MB by default
7 . 1
EXAMPLES
8 . 1
Publishing API for 1:N communication
nc, err := nats.Connect("nats://demo.nats.io:4222")
if err != nil {
log.Fatalf("Failed to connect: %sn", err)
}
nc.Subscribe("hello", func(m *nats.Msg) {
log.Printf("Received message: %sn", string(m.Data))
})
// Broadcast message to all subscribed to 'hello'
err := nc.Publish("hello", []byte("world"))
if err != nil {
log.Printf("Error publishing payload: %sn", err)
}
9 . 1
Request/Response API for 1:1 communication
nc, err := nats.Connect("nats://demo.nats.io:4222")
if err != nil {
log.Fatalf("Failed to connect: %sn", err)
}
// Receive requests on the 'help' subject...
nc.Subscribe("help", func(m *nats.Msg) {
log.Printf("Received message: %sn", string(m.Data))
nc.Publish(m.Reply, []byte("ok can help"))
})
// Wait for 2 seconds for response or give up
result, err := nc.Request("help", []byte("please"), 2*time.Second)
if err != nil {
log.Printf("Error receiving response: %sn", err)
} else {
log.Printf("Result: %vn", string(result.Data))
}
10 . 1
"❗"❗
Request/Response API takes a timeout before giving
up, blocking until getting either a response or an
error.
result, err := nc.Request("help", []byte("please"), 2*time.Second)
if err != nil {
log.Printf("Error receiving response: %sn", err)
}
11 . 1
Shortcoming: there is no way to cancel the request!
Could this be improved somehow?
result, err := nc.Request("help", []byte("please"), 2*time.Second)
if err != nil {
log.Printf("Error receiving response: %sn", err)
}
12 . 1
Cancellation in Golang: Background
The Done() channel
https://blog.golang.org/pipelines
13 . 1
Cancellation in Golang: Background
The Context interface
https://blog.golang.org/context
14 . 1
The context package
Since Go 1.7, included in standard library ✅
import "context"
15 . 1
Current status
Now many library authors are looking into adopting!
% % %
(GH query) Add context.Context extension:go state:open
16 . 1
17 . 1
Standard library continuously adopting Context too.
■ net
■ net/http
■ database/sql
func (d *Dialer) DialContext(ctx context.Context, network, address string)
func (r *Request) WithContext(ctx context.Context) *Request
func (db *DB) BeginTx(ctx context.Context, opts *TxOptions) (*Tx, error)
18 . 1
TIP
If it is a blocking call in a library, it will probably benefit
from adding context.Context support soon.
19 . 1
Ok, so how exactly is Context used?
20 . 1
The Context toolkit
type Context interface {
Deadline() (deadline time.Time, ok bool)
Done() <-chan struct{}
Err() error
Value(key interface{}) interface{}
}
type Context
func Background() Context
func TODO() Context
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
func WithValue(parent Context, key, val interface{}) Context
21 . 1
HTTP Example
req, _ := http.NewRequest("GET", "http://demo.nats.io:8222/varz", nil)
// Parent context
ctx := context.Background()
// Timeout context
ctx, cancel := context.WithTimeout(ctx, 500*time.Millisecond)
// Must always call the cancellation function!
defer cancel()
// Wrap request with the timeout context
req = req.WithContext(ctx)
result, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatalf("Error: %sn", err)
}
22 . 1
2 types of errors:
■ context.DeadlineExceeded (← net.Error)
■ context.Canceled
Error: Get http://demo.nats.io:8222/varz: context deadline exceeded
exit status 1
Error: Get http://demo.nats.io:8222/varz: context canceled
exit status 1
23 . 1
Cool! ⭐ Now let's add support for Context in the
NATS client.
24 . 1
What is a NATS Request?
Essentially, it waits for this to happen in the network:
# --> Request
SUB _INBOX.ioL1Ws5aZZf5fyeF6sAdjw 2
UNSUB 2 1
PUB help _INBOX.ioL1Ws5aZZf5fyeF6sAdjw 6
please
# <-- Response
MSG _INBOX.ioL1Ws5aZZf5fyeF6sAdjw 2 11
ok can help
25 . 1
What is a NATS Request?
Request API:
Syntactic sugar for this under the hood:
result, err := nc.Request("help", []byte("please"), 2*time.Second)
// Ephemeral subscription for request
inbox := NewInbox()
s, _ := nc.SubscribeSync(inbox)
// Expect single response
s.AutoUnsubscribe(1)
defer s.Unsubscribe()
// Announce request and reply inbox
nc.PublishRequest("help", inbox, []byte("please"))
// Wait for reply (*blocks here*)
msg, _ := s.NextMsg(timeout)
26 . 1
Adding context to NATS Requests
First step, add new context aware API for the
subscriptions to yield the next message or give up if
context is done.
// Classic
func (s *Subscription) NextMsg(timeout time.Duration) (*Msg, error)
// Context Aware API
func (s *Subscription) NextMsgWithContext(ctx context.Context) (*Msg, error)
27 . 1
(Just in case) To avoid breaking previous compatibility,
add new functionality into a context.go file and
add build tag to only support above Go17.
// Copyright 2012-2017 Apcera Inc. All rights reserved.
// +build go1.7
// A Go client for the NATS messaging system (https://nats.io).
package nats
import (
"context"
)
28 . 1
Enhancing NextMsg with Context capabilities
Without Context (code was simplified):
func (s *Subscription) NextMsg(timeout time.Duration) (*Msg, error) {
// Subscription channel over which we receive messages
mch := s.mch
var ok bool
var msg *Msg
t := time.NewTimer(timeout) //
defer t.Stop()
// Wait to receive message...
select {
case msg, ok = <-mch:
if !ok {
return nil, ErrConnectionClosed
}
case <-t.C: ' // ...or timer to expire
return nil, ErrTimeout
}
return msg, nil
29 . 1
First pass
How about making Subscription context aware?
// A Subscription represents interest in a given subject.
type Subscription struct {
// context used along with the subscription.
ctx cntxt
// ...
func (s *Subscription) NextMsgWithContext(ctx context.Context) (*Msg, error) {
// Call NextMsg from subscription but disabling the timeout
// as we rely on the context for the cancellation instead.
s.SetContext(ctx)
msg, err := s.NextMsg(0)
if err != nil {
select {
case <-ctx.Done():
return nil, ctx.Err()
default:
}
}
30 . 1
net/http uses this style
type Request struct {
// ctx is either the client or server context. It should only
// be modified via copying the whole Request using WithContext.
// It is unexported to prevent people from using Context wrong
// and mutating the contexts held by callers of the same request.
ctx context.Context
}
// WithContext returns a shallow copy of r with its context changed
// to ctx. The provided ctx must be non-nil.
func (r *Request) WithContext(ctx context.Context) *Request {
if ctx == nil {
panic("nil context")
}
r2 := new(Request)
*r2 = *r
r2.ctx = ctx
return r2
}
31 . 1
❌ style not recommended
32 . 1
Enhancing NextMsg with Context capabilities
Without Context (code was simplified):
func (s *Subscription) NextMsg(timeout time.Duration) (*Msg, error) {
// Subscription channel over which we receive messages
mch := s.mch
var ok bool
var msg *Msg
t := time.NewTimer(timeout) //
defer t.Stop()
// Wait to receive message...
select {
case msg, ok = <-mch:
if !ok {
return nil, ErrConnectionClosed
}
case <-t.C: ' // ...or timer to expire
return nil, ErrTimeout
}
return msg, nil
33 . 1
Enhancing NextMsg with Context capabilities
With Context:
func (s *Subscription) NextMsgWithContext(ctx context.Context) (*Msg, error) {
// Subscription channel over which we receive messages
mch := s.mch
var ok bool
var msg *Msg
// Wait to receive message...
select {
case msg, ok = <-mch:
if !ok {
return nil, ErrConnectionClosed
}
case <-ctx.Done(): ' // ...or Context to be done
return nil, ctx.Err()
}
return msg, nil
34 . 1
Learning from the standard library
panic in case nil is passed?
func (r *Request) WithContext(ctx context.Context) *Request {
if ctx == nil {
panic("nil context")
}
func (d *Dialer) DialContext(ctx context.Context, network, address string) (Conn, error)
if ctx == nil {
panic("nil context")
}
func CommandContext(ctx context.Context, name string, arg ...string) *Cmd {
if ctx == nil {
panic("nil Context")
}
35 . 1
Learning from the standard library
panic is not common in the client library so we've
added custom error for now instead
func (s *Subscription) NextMsgWithContext(ctx context.Context) (*Msg, error) {
if ctx == nil {
return nil, ErrInvalidContext
}
36 . 1
Once we have NextMsgWithContext, we can build
on it to add support for RequestWithContext
func (nc *Conn) RequestWithContext(ctx context.Context, subj string, data []byte) (
*Msg, error,
) {
// Ephemeral subscription for request
inbox := NewInbox()
s, _ := nc.SubscribeSync(inbox)
// Expect single response
s.AutoUnsubscribe(1)
defer s.Unsubscribe()
// Announce request and reply inbox
nc.PublishRequest(subj, inbox, data))
// Wait for reply or context to be done
return s.NextMsgWithContext(ctx)
37 . 1
And that's it!
We now have context.Context support ✌
38 . 1
NATS Request Example
nc, _ := nats.Connect("nats://demo.nats.io:4222")
nc.Subscribe("help", func(m *nats.Msg) {
log.Printf("Received message: %sn", string(m.Data))
nc.Publish(m.Reply, []byte("ok can help"))
})
// Parent context
ctx := context.Background()
ctx, cancel := context.WithTimeout(ctx, 2*time.Second)
defer cancel()
// Blocks until receiving request or context is done
result, err := nc.RequestWithContext(ctx, "help", []byte("please"))
if err != nil {
log.Printf("Error receiving response: %sn", err)
} else {
log.Printf("Result: %vn", string(result.Data))
}
39 . 1
Cool feature: Cancellation propagation
Start from a parent context and chain the rest
Opens the door for more advanced use cases without
affecting readability too much.
context.Background()
!"" context.WithDeadline(...)
!"" context.WithTimeout(...)
40 . 1
Advanced usage with cancellation
Example: Probe Request
Goal: Gather as many messages as we can within 1s or
until we have been idle without receiving replies for
250ms
41 . 1
Expressed in terms of Context
// Parent context
ctx := context.Background()
// Probing context with hard deadline to 1s
ctx, done := context.WithTimeout(ctx, 1*time.Second)
defer done() // must be called always
// Probe deadline will be expanded as we gather replies
timer := time.AfterFunc(250*time.Millisecond, func() {
done()
})
// ↑ (timer will be reset once a message is received)
42 . 1
Expressed in terms of Context (cont'd)
inbox := nats.NewInbox()
sub, _ := nc.SubscribeSync(inbox)
defer sub.Unsubscribe()
start := time.Now()
nc.PublishRequest("help", inbox, []byte("please help!"))
replies := make([]*Msg, 0)
for {
// Receive as many messages as we can in 1s or until we stop
// receiving new messages for over 250ms.
result, err := sub.NextMsgWithContext(ctx)
if err != nil {
break
}
replies = append(replies, result)
timer.Reset(250 * time.Millisecond) ' // reset timer! *
}
log.Printf("Received %d messages in %.3f seconds", len(replies), time.Since(start).Secon
43 . 1
Expressed in terms of Context (cont'd)
nc.Subscribe("help", func(m *nats.Msg) {
log.Printf("Received help request: %sn", string(m.Data))
for i := 0; i < 100; i++ {
// Starts to increase latency after a couple of requests
if i >= 3 {
time.Sleep(300 * time.Millisecond)
}
nc.Publish(m.Reply, []byte("ok can help"))
log.Printf("Replied to help request (times=%d)n", i)
time.Sleep(100 * time.Millisecond)
}
})
44 . 1
We could do a pretty advanced usage of the NATS
library without writing a single select or more
goroutines!
45 . 1
CONCLUSIONS
If a call blocks in your library, it will probably
eventually require context.Context support.
Some refactoring might be involved…
Catchup with the ecosystem!
context.Context based code composes nicely
so makes up for very readable code
Always call the cancellation function to avoid
leaking resources! +
46 . 1
THANKS!
/
Twitter:
github.com/nats-io @nats_io
@wallyqs
47 . 1

Contenu connexe

Tendances

Commication Framework in OpenStack
Commication Framework in OpenStackCommication Framework in OpenStack
Commication Framework in OpenStackSean Chang
 
Anatomy of neutron from the eagle eyes of troubelshoorters
Anatomy of neutron from the eagle eyes of troubelshoortersAnatomy of neutron from the eagle eyes of troubelshoorters
Anatomy of neutron from the eagle eyes of troubelshoortersSadique Puthen
 
Netty from the trenches
Netty from the trenchesNetty from the trenches
Netty from the trenchesJordi Gerona
 
Simple Solutions for Complex Problems - Boulder Meetup
Simple Solutions for Complex Problems - Boulder MeetupSimple Solutions for Complex Problems - Boulder Meetup
Simple Solutions for Complex Problems - Boulder MeetupApcera
 
Building scalable network applications with Netty (as presented on NLJUG JFal...
Building scalable network applications with Netty (as presented on NLJUG JFal...Building scalable network applications with Netty (as presented on NLJUG JFal...
Building scalable network applications with Netty (as presented on NLJUG JFal...Jaap ter Woerds
 
Apache httpd reverse proxy and Tomcat
Apache httpd reverse proxy and TomcatApache httpd reverse proxy and Tomcat
Apache httpd reverse proxy and TomcatJean-Frederic Clere
 
Multi tier-app-network-topology-neutron-final
Multi tier-app-network-topology-neutron-finalMulti tier-app-network-topology-neutron-final
Multi tier-app-network-topology-neutron-finalSadique Puthen
 
Openstack on Fedora, Fedora on Openstack: An Introduction to cloud IaaS
Openstack on Fedora, Fedora on Openstack: An Introduction to cloud IaaSOpenstack on Fedora, Fedora on Openstack: An Introduction to cloud IaaS
Openstack on Fedora, Fedora on Openstack: An Introduction to cloud IaaSSadique Puthen
 
OpenStack networking
OpenStack networkingOpenStack networking
OpenStack networkingSim Janghoon
 
NATS for Rubyists - Tokyo Rubyist Meetup
NATS for Rubyists - Tokyo Rubyist MeetupNATS for Rubyists - Tokyo Rubyist Meetup
NATS for Rubyists - Tokyo Rubyist Meetupwallyqs
 
Testing Wi-Fi with OSS Tools
Testing Wi-Fi with OSS ToolsTesting Wi-Fi with OSS Tools
Testing Wi-Fi with OSS ToolsAll Things Open
 
Openstack Networking Internals - first part
Openstack Networking Internals - first partOpenstack Networking Internals - first part
Openstack Networking Internals - first partlilliput12
 
Monitoring with Prometheus
Monitoring with PrometheusMonitoring with Prometheus
Monitoring with PrometheusShiao-An Yuan
 
Apache httpd 2.4 Reverse Proxy
Apache httpd 2.4 Reverse ProxyApache httpd 2.4 Reverse Proxy
Apache httpd 2.4 Reverse ProxyJim Jagielski
 

Tendances (17)

Commication Framework in OpenStack
Commication Framework in OpenStackCommication Framework in OpenStack
Commication Framework in OpenStack
 
Anatomy of neutron from the eagle eyes of troubelshoorters
Anatomy of neutron from the eagle eyes of troubelshoortersAnatomy of neutron from the eagle eyes of troubelshoorters
Anatomy of neutron from the eagle eyes of troubelshoorters
 
Reactive server with netty
Reactive server with nettyReactive server with netty
Reactive server with netty
 
Netty from the trenches
Netty from the trenchesNetty from the trenches
Netty from the trenches
 
Simple Solutions for Complex Problems - Boulder Meetup
Simple Solutions for Complex Problems - Boulder MeetupSimple Solutions for Complex Problems - Boulder Meetup
Simple Solutions for Complex Problems - Boulder Meetup
 
Building scalable network applications with Netty (as presented on NLJUG JFal...
Building scalable network applications with Netty (as presented on NLJUG JFal...Building scalable network applications with Netty (as presented on NLJUG JFal...
Building scalable network applications with Netty (as presented on NLJUG JFal...
 
Apache httpd reverse proxy and Tomcat
Apache httpd reverse proxy and TomcatApache httpd reverse proxy and Tomcat
Apache httpd reverse proxy and Tomcat
 
Multi tier-app-network-topology-neutron-final
Multi tier-app-network-topology-neutron-finalMulti tier-app-network-topology-neutron-final
Multi tier-app-network-topology-neutron-final
 
Openstack on Fedora, Fedora on Openstack: An Introduction to cloud IaaS
Openstack on Fedora, Fedora on Openstack: An Introduction to cloud IaaSOpenstack on Fedora, Fedora on Openstack: An Introduction to cloud IaaS
Openstack on Fedora, Fedora on Openstack: An Introduction to cloud IaaS
 
OpenStack networking
OpenStack networkingOpenStack networking
OpenStack networking
 
NATS for Rubyists - Tokyo Rubyist Meetup
NATS for Rubyists - Tokyo Rubyist MeetupNATS for Rubyists - Tokyo Rubyist Meetup
NATS for Rubyists - Tokyo Rubyist Meetup
 
Testing Wi-Fi with OSS Tools
Testing Wi-Fi with OSS ToolsTesting Wi-Fi with OSS Tools
Testing Wi-Fi with OSS Tools
 
Openstack Networking Internals - first part
Openstack Networking Internals - first partOpenstack Networking Internals - first part
Openstack Networking Internals - first part
 
Docker and Fargate
Docker and FargateDocker and Fargate
Docker and Fargate
 
Monitoring with Prometheus
Monitoring with PrometheusMonitoring with Prometheus
Monitoring with Prometheus
 
Apache ZooKeeper
Apache ZooKeeperApache ZooKeeper
Apache ZooKeeper
 
Apache httpd 2.4 Reverse Proxy
Apache httpd 2.4 Reverse ProxyApache httpd 2.4 Reverse Proxy
Apache httpd 2.4 Reverse Proxy
 

Similaire à GopherFest 2017 - Adding Context to NATS

Simple and Scalable Microservices: Using NATS with Docker Compose and Swarm
Simple and Scalable Microservices: Using NATS with Docker Compose and Swarm Simple and Scalable Microservices: Using NATS with Docker Compose and Swarm
Simple and Scalable Microservices: Using NATS with Docker Compose and Swarm NATS
 
Simple and Scalable Microservices: Using NATS with Docker Compose and Swarm
Simple and Scalable Microservices: Using NATS with Docker Compose and SwarmSimple and Scalable Microservices: Using NATS with Docker Compose and Swarm
Simple and Scalable Microservices: Using NATS with Docker Compose and SwarmApcera
 
Simple, Secure, Scalable Messaging for the Cloud Native Era - AllThingsOpen 2...
Simple, Secure, Scalable Messaging for the Cloud Native Era - AllThingsOpen 2...Simple, Secure, Scalable Messaging for the Cloud Native Era - AllThingsOpen 2...
Simple, Secure, Scalable Messaging for the Cloud Native Era - AllThingsOpen 2...NATS
 
NATS: Simple, Secure, and Scalable Messaging for the Cloud Native Era
NATS: Simple, Secure, and Scalable Messaging for the Cloud Native EraNATS: Simple, Secure, and Scalable Messaging for the Cloud Native Era
NATS: Simple, Secure, and Scalable Messaging for the Cloud Native EraAll Things Open
 
Writing Networking Clients in Go - GopherCon 2017 talk
Writing Networking Clients in Go - GopherCon 2017 talkWriting Networking Clients in Go - GopherCon 2017 talk
Writing Networking Clients in Go - GopherCon 2017 talkNATS
 
От Java Threads к лямбдам, Андрей Родионов
От Java Threads к лямбдам, Андрей РодионовОт Java Threads к лямбдам, Андрей Родионов
От Java Threads к лямбдам, Андрей РодионовYandex
 
Preview of Apache Pulsar 2.5.0
Preview of Apache Pulsar 2.5.0Preview of Apache Pulsar 2.5.0
Preview of Apache Pulsar 2.5.0StreamNative
 
Microservices Meetup San Francisco - August 2017 Talk on NATS
Microservices Meetup San Francisco - August 2017 Talk on NATSMicroservices Meetup San Francisco - August 2017 Talk on NATS
Microservices Meetup San Francisco - August 2017 Talk on NATSNATS
 
Cassandra 2.1 boot camp, Overview
Cassandra 2.1 boot camp, OverviewCassandra 2.1 boot camp, Overview
Cassandra 2.1 boot camp, OverviewJoshua McKenzie
 
Taming Cloud APIs with Swift
Taming Cloud APIs with SwiftTaming Cloud APIs with Swift
Taming Cloud APIs with SwiftTim Burks
 
От Java Threads к лямбдам, Андрей Родионов
От Java Threads к лямбдам, Андрей РодионовОт Java Threads к лямбдам, Андрей Родионов
От Java Threads к лямбдам, Андрей РодионовYandex
 
NET Systems Programming Learned the Hard Way.pptx
NET Systems Programming Learned the Hard Way.pptxNET Systems Programming Learned the Hard Way.pptx
NET Systems Programming Learned the Hard Way.pptxpetabridge
 
Protobuf & Code Generation + Go-Kit
Protobuf & Code Generation + Go-KitProtobuf & Code Generation + Go-Kit
Protobuf & Code Generation + Go-KitManfred Touron
 
Cotopaxi - IoT testing toolkit (Black Hat Asia 2019 Arsenal)
Cotopaxi - IoT testing toolkit (Black Hat Asia 2019 Arsenal)Cotopaxi - IoT testing toolkit (Black Hat Asia 2019 Arsenal)
Cotopaxi - IoT testing toolkit (Black Hat Asia 2019 Arsenal)Jakub Botwicz
 
The Zen of High Performance Messaging with NATS
The Zen of High Performance Messaging with NATSThe Zen of High Performance Messaging with NATS
The Zen of High Performance Messaging with NATSApcera
 
The Zen of High Performance Messaging with NATS
The Zen of High Performance Messaging with NATS The Zen of High Performance Messaging with NATS
The Zen of High Performance Messaging with NATS NATS
 
Capturing NIC and Kernel TX and RX Timestamps for Packets in Go
Capturing NIC and Kernel TX and RX Timestamps for Packets in GoCapturing NIC and Kernel TX and RX Timestamps for Packets in Go
Capturing NIC and Kernel TX and RX Timestamps for Packets in GoScyllaDB
 
Guaranteed Event Delivery with Kafka and NodeJS | Amitesh Madhur, Nutanix
Guaranteed Event Delivery with Kafka and NodeJS | Amitesh Madhur, NutanixGuaranteed Event Delivery with Kafka and NodeJS | Amitesh Madhur, Nutanix
Guaranteed Event Delivery with Kafka and NodeJS | Amitesh Madhur, NutanixHostedbyConfluent
 

Similaire à GopherFest 2017 - Adding Context to NATS (20)

Simple and Scalable Microservices: Using NATS with Docker Compose and Swarm
Simple and Scalable Microservices: Using NATS with Docker Compose and Swarm Simple and Scalable Microservices: Using NATS with Docker Compose and Swarm
Simple and Scalable Microservices: Using NATS with Docker Compose and Swarm
 
Simple and Scalable Microservices: Using NATS with Docker Compose and Swarm
Simple and Scalable Microservices: Using NATS with Docker Compose and SwarmSimple and Scalable Microservices: Using NATS with Docker Compose and Swarm
Simple and Scalable Microservices: Using NATS with Docker Compose and Swarm
 
Simple, Secure, Scalable Messaging for the Cloud Native Era - AllThingsOpen 2...
Simple, Secure, Scalable Messaging for the Cloud Native Era - AllThingsOpen 2...Simple, Secure, Scalable Messaging for the Cloud Native Era - AllThingsOpen 2...
Simple, Secure, Scalable Messaging for the Cloud Native Era - AllThingsOpen 2...
 
NATS: Simple, Secure, and Scalable Messaging for the Cloud Native Era
NATS: Simple, Secure, and Scalable Messaging for the Cloud Native EraNATS: Simple, Secure, and Scalable Messaging for the Cloud Native Era
NATS: Simple, Secure, and Scalable Messaging for the Cloud Native Era
 
Writing Networking Clients in Go - GopherCon 2017 talk
Writing Networking Clients in Go - GopherCon 2017 talkWriting Networking Clients in Go - GopherCon 2017 talk
Writing Networking Clients in Go - GopherCon 2017 talk
 
От Java Threads к лямбдам, Андрей Родионов
От Java Threads к лямбдам, Андрей РодионовОт Java Threads к лямбдам, Андрей Родионов
От Java Threads к лямбдам, Андрей Родионов
 
Preview of Apache Pulsar 2.5.0
Preview of Apache Pulsar 2.5.0Preview of Apache Pulsar 2.5.0
Preview of Apache Pulsar 2.5.0
 
Microservices Meetup San Francisco - August 2017 Talk on NATS
Microservices Meetup San Francisco - August 2017 Talk on NATSMicroservices Meetup San Francisco - August 2017 Talk on NATS
Microservices Meetup San Francisco - August 2017 Talk on NATS
 
Cassandra 2.1 boot camp, Overview
Cassandra 2.1 boot camp, OverviewCassandra 2.1 boot camp, Overview
Cassandra 2.1 boot camp, Overview
 
Apache Kafka Demo
Apache Kafka DemoApache Kafka Demo
Apache Kafka Demo
 
Taming Cloud APIs with Swift
Taming Cloud APIs with SwiftTaming Cloud APIs with Swift
Taming Cloud APIs with Swift
 
gRPC in Go
gRPC in GogRPC in Go
gRPC in Go
 
От Java Threads к лямбдам, Андрей Родионов
От Java Threads к лямбдам, Андрей РодионовОт Java Threads к лямбдам, Андрей Родионов
От Java Threads к лямбдам, Андрей Родионов
 
NET Systems Programming Learned the Hard Way.pptx
NET Systems Programming Learned the Hard Way.pptxNET Systems Programming Learned the Hard Way.pptx
NET Systems Programming Learned the Hard Way.pptx
 
Protobuf & Code Generation + Go-Kit
Protobuf & Code Generation + Go-KitProtobuf & Code Generation + Go-Kit
Protobuf & Code Generation + Go-Kit
 
Cotopaxi - IoT testing toolkit (Black Hat Asia 2019 Arsenal)
Cotopaxi - IoT testing toolkit (Black Hat Asia 2019 Arsenal)Cotopaxi - IoT testing toolkit (Black Hat Asia 2019 Arsenal)
Cotopaxi - IoT testing toolkit (Black Hat Asia 2019 Arsenal)
 
The Zen of High Performance Messaging with NATS
The Zen of High Performance Messaging with NATSThe Zen of High Performance Messaging with NATS
The Zen of High Performance Messaging with NATS
 
The Zen of High Performance Messaging with NATS
The Zen of High Performance Messaging with NATS The Zen of High Performance Messaging with NATS
The Zen of High Performance Messaging with NATS
 
Capturing NIC and Kernel TX and RX Timestamps for Packets in Go
Capturing NIC and Kernel TX and RX Timestamps for Packets in GoCapturing NIC and Kernel TX and RX Timestamps for Packets in Go
Capturing NIC and Kernel TX and RX Timestamps for Packets in Go
 
Guaranteed Event Delivery with Kafka and NodeJS | Amitesh Madhur, Nutanix
Guaranteed Event Delivery with Kafka and NodeJS | Amitesh Madhur, NutanixGuaranteed Event Delivery with Kafka and NodeJS | Amitesh Madhur, Nutanix
Guaranteed Event Delivery with Kafka and NodeJS | Amitesh Madhur, Nutanix
 

Plus de wallyqs

GoSF: Decoupling Services from IP networks with NATS
GoSF: Decoupling Services from IP networks with NATSGoSF: Decoupling Services from IP networks with NATS
GoSF: Decoupling Services from IP networks with NATSwallyqs
 
OSCON: Building Cloud Native Apps with NATS
OSCON:  Building Cloud Native Apps with NATSOSCON:  Building Cloud Native Apps with NATS
OSCON: Building Cloud Native Apps with NATSwallyqs
 
SF Python Meetup - Introduction to NATS Messaging with Python3
SF Python Meetup - Introduction to NATS Messaging with Python3SF Python Meetup - Introduction to NATS Messaging with Python3
SF Python Meetup - Introduction to NATS Messaging with Python3wallyqs
 
Connect Everything with NATS - Cloud Expo Europe
Connect Everything with NATS - Cloud Expo EuropeConnect Everything with NATS - Cloud Expo Europe
Connect Everything with NATS - Cloud Expo Europewallyqs
 
KubeCon NA 2018 - NATS Deep Dive: The Evolution of NATS
KubeCon NA 2018 - NATS Deep Dive: The Evolution of NATSKubeCon NA 2018 - NATS Deep Dive: The Evolution of NATS
KubeCon NA 2018 - NATS Deep Dive: The Evolution of NATSwallyqs
 
KubeConEU - NATS Deep Dive
KubeConEU - NATS Deep DiveKubeConEU - NATS Deep Dive
KubeConEU - NATS Deep Divewallyqs
 
RustなNATSのClientを作ってみた
RustなNATSのClientを作ってみたRustなNATSのClientを作ってみた
RustなNATSのClientを作ってみたwallyqs
 
サルでもわかるMesos schedulerの作り方
サルでもわかるMesos schedulerの作り方サルでもわかるMesos schedulerの作り方
サルでもわかるMesos schedulerの作り方wallyqs
 

Plus de wallyqs (8)

GoSF: Decoupling Services from IP networks with NATS
GoSF: Decoupling Services from IP networks with NATSGoSF: Decoupling Services from IP networks with NATS
GoSF: Decoupling Services from IP networks with NATS
 
OSCON: Building Cloud Native Apps with NATS
OSCON:  Building Cloud Native Apps with NATSOSCON:  Building Cloud Native Apps with NATS
OSCON: Building Cloud Native Apps with NATS
 
SF Python Meetup - Introduction to NATS Messaging with Python3
SF Python Meetup - Introduction to NATS Messaging with Python3SF Python Meetup - Introduction to NATS Messaging with Python3
SF Python Meetup - Introduction to NATS Messaging with Python3
 
Connect Everything with NATS - Cloud Expo Europe
Connect Everything with NATS - Cloud Expo EuropeConnect Everything with NATS - Cloud Expo Europe
Connect Everything with NATS - Cloud Expo Europe
 
KubeCon NA 2018 - NATS Deep Dive: The Evolution of NATS
KubeCon NA 2018 - NATS Deep Dive: The Evolution of NATSKubeCon NA 2018 - NATS Deep Dive: The Evolution of NATS
KubeCon NA 2018 - NATS Deep Dive: The Evolution of NATS
 
KubeConEU - NATS Deep Dive
KubeConEU - NATS Deep DiveKubeConEU - NATS Deep Dive
KubeConEU - NATS Deep Dive
 
RustなNATSのClientを作ってみた
RustなNATSのClientを作ってみたRustなNATSのClientを作ってみた
RustなNATSのClientを作ってみた
 
サルでもわかるMesos schedulerの作り方
サルでもわかるMesos schedulerの作り方サルでもわかるMesos schedulerの作り方
サルでもわかるMesos schedulerの作り方
 

Dernier

Work Experience-Dalton Park.pptxfvvvvvvv
Work Experience-Dalton Park.pptxfvvvvvvvWork Experience-Dalton Park.pptxfvvvvvvv
Work Experience-Dalton Park.pptxfvvvvvvvLewisJB
 
Arduino_CSE ece ppt for working and principal of arduino.ppt
Arduino_CSE ece ppt for working and principal of arduino.pptArduino_CSE ece ppt for working and principal of arduino.ppt
Arduino_CSE ece ppt for working and principal of arduino.pptSAURABHKUMAR892774
 
Unit7-DC_Motors nkkjnsdkfnfcdfknfdgfggfg
Unit7-DC_Motors nkkjnsdkfnfcdfknfdgfggfgUnit7-DC_Motors nkkjnsdkfnfcdfknfdgfggfg
Unit7-DC_Motors nkkjnsdkfnfcdfknfdgfggfgsaravananr517913
 
"Exploring the Essential Functions and Design Considerations of Spillways in ...
"Exploring the Essential Functions and Design Considerations of Spillways in ..."Exploring the Essential Functions and Design Considerations of Spillways in ...
"Exploring the Essential Functions and Design Considerations of Spillways in ...Erbil Polytechnic University
 
DM Pillar Training Manual.ppt will be useful in deploying TPM in project
DM Pillar Training Manual.ppt will be useful in deploying TPM in projectDM Pillar Training Manual.ppt will be useful in deploying TPM in project
DM Pillar Training Manual.ppt will be useful in deploying TPM in projectssuserb6619e
 
Crystal Structure analysis and detailed information pptx
Crystal Structure analysis and detailed information pptxCrystal Structure analysis and detailed information pptx
Crystal Structure analysis and detailed information pptxachiever3003
 
11. Properties of Liquid Fuels in Energy Engineering.pdf
11. Properties of Liquid Fuels in Energy Engineering.pdf11. Properties of Liquid Fuels in Energy Engineering.pdf
11. Properties of Liquid Fuels in Energy Engineering.pdfHafizMudaserAhmad
 
Correctly Loading Incremental Data at Scale
Correctly Loading Incremental Data at ScaleCorrectly Loading Incremental Data at Scale
Correctly Loading Incremental Data at ScaleAlluxio, Inc.
 
Gravity concentration_MI20612MI_________
Gravity concentration_MI20612MI_________Gravity concentration_MI20612MI_________
Gravity concentration_MI20612MI_________Romil Mishra
 
List of Accredited Concrete Batching Plant.pdf
List of Accredited Concrete Batching Plant.pdfList of Accredited Concrete Batching Plant.pdf
List of Accredited Concrete Batching Plant.pdfisabel213075
 
multiple access in wireless communication
multiple access in wireless communicationmultiple access in wireless communication
multiple access in wireless communicationpanditadesh123
 
Software and Systems Engineering Standards: Verification and Validation of Sy...
Software and Systems Engineering Standards: Verification and Validation of Sy...Software and Systems Engineering Standards: Verification and Validation of Sy...
Software and Systems Engineering Standards: Verification and Validation of Sy...VICTOR MAESTRE RAMIREZ
 
Input Output Management in Operating System
Input Output Management in Operating SystemInput Output Management in Operating System
Input Output Management in Operating SystemRashmi Bhat
 
Cooling Tower SERD pH drop issue (11 April 2024) .pptx
Cooling Tower SERD pH drop issue (11 April 2024) .pptxCooling Tower SERD pH drop issue (11 April 2024) .pptx
Cooling Tower SERD pH drop issue (11 April 2024) .pptxmamansuratman0253
 
Research Methodology for Engineering pdf
Research Methodology for Engineering pdfResearch Methodology for Engineering pdf
Research Methodology for Engineering pdfCaalaaAbdulkerim
 
US Department of Education FAFSA Week of Action
US Department of Education FAFSA Week of ActionUS Department of Education FAFSA Week of Action
US Department of Education FAFSA Week of ActionMebane Rash
 
Ch10-Global Supply Chain - Cadena de Suministro.pdf
Ch10-Global Supply Chain - Cadena de Suministro.pdfCh10-Global Supply Chain - Cadena de Suministro.pdf
Ch10-Global Supply Chain - Cadena de Suministro.pdfChristianCDAM
 
System Simulation and Modelling with types and Event Scheduling
System Simulation and Modelling with types and Event SchedulingSystem Simulation and Modelling with types and Event Scheduling
System Simulation and Modelling with types and Event SchedulingBootNeck1
 

Dernier (20)

Work Experience-Dalton Park.pptxfvvvvvvv
Work Experience-Dalton Park.pptxfvvvvvvvWork Experience-Dalton Park.pptxfvvvvvvv
Work Experience-Dalton Park.pptxfvvvvvvv
 
Arduino_CSE ece ppt for working and principal of arduino.ppt
Arduino_CSE ece ppt for working and principal of arduino.pptArduino_CSE ece ppt for working and principal of arduino.ppt
Arduino_CSE ece ppt for working and principal of arduino.ppt
 
Unit7-DC_Motors nkkjnsdkfnfcdfknfdgfggfg
Unit7-DC_Motors nkkjnsdkfnfcdfknfdgfggfgUnit7-DC_Motors nkkjnsdkfnfcdfknfdgfggfg
Unit7-DC_Motors nkkjnsdkfnfcdfknfdgfggfg
 
"Exploring the Essential Functions and Design Considerations of Spillways in ...
"Exploring the Essential Functions and Design Considerations of Spillways in ..."Exploring the Essential Functions and Design Considerations of Spillways in ...
"Exploring the Essential Functions and Design Considerations of Spillways in ...
 
DM Pillar Training Manual.ppt will be useful in deploying TPM in project
DM Pillar Training Manual.ppt will be useful in deploying TPM in projectDM Pillar Training Manual.ppt will be useful in deploying TPM in project
DM Pillar Training Manual.ppt will be useful in deploying TPM in project
 
Design and analysis of solar grass cutter.pdf
Design and analysis of solar grass cutter.pdfDesign and analysis of solar grass cutter.pdf
Design and analysis of solar grass cutter.pdf
 
Crystal Structure analysis and detailed information pptx
Crystal Structure analysis and detailed information pptxCrystal Structure analysis and detailed information pptx
Crystal Structure analysis and detailed information pptx
 
11. Properties of Liquid Fuels in Energy Engineering.pdf
11. Properties of Liquid Fuels in Energy Engineering.pdf11. Properties of Liquid Fuels in Energy Engineering.pdf
11. Properties of Liquid Fuels in Energy Engineering.pdf
 
Correctly Loading Incremental Data at Scale
Correctly Loading Incremental Data at ScaleCorrectly Loading Incremental Data at Scale
Correctly Loading Incremental Data at Scale
 
Gravity concentration_MI20612MI_________
Gravity concentration_MI20612MI_________Gravity concentration_MI20612MI_________
Gravity concentration_MI20612MI_________
 
List of Accredited Concrete Batching Plant.pdf
List of Accredited Concrete Batching Plant.pdfList of Accredited Concrete Batching Plant.pdf
List of Accredited Concrete Batching Plant.pdf
 
multiple access in wireless communication
multiple access in wireless communicationmultiple access in wireless communication
multiple access in wireless communication
 
Software and Systems Engineering Standards: Verification and Validation of Sy...
Software and Systems Engineering Standards: Verification and Validation of Sy...Software and Systems Engineering Standards: Verification and Validation of Sy...
Software and Systems Engineering Standards: Verification and Validation of Sy...
 
Input Output Management in Operating System
Input Output Management in Operating SystemInput Output Management in Operating System
Input Output Management in Operating System
 
Cooling Tower SERD pH drop issue (11 April 2024) .pptx
Cooling Tower SERD pH drop issue (11 April 2024) .pptxCooling Tower SERD pH drop issue (11 April 2024) .pptx
Cooling Tower SERD pH drop issue (11 April 2024) .pptx
 
Research Methodology for Engineering pdf
Research Methodology for Engineering pdfResearch Methodology for Engineering pdf
Research Methodology for Engineering pdf
 
US Department of Education FAFSA Week of Action
US Department of Education FAFSA Week of ActionUS Department of Education FAFSA Week of Action
US Department of Education FAFSA Week of Action
 
POWER SYSTEMS-1 Complete notes examples
POWER SYSTEMS-1 Complete notes  examplesPOWER SYSTEMS-1 Complete notes  examples
POWER SYSTEMS-1 Complete notes examples
 
Ch10-Global Supply Chain - Cadena de Suministro.pdf
Ch10-Global Supply Chain - Cadena de Suministro.pdfCh10-Global Supply Chain - Cadena de Suministro.pdf
Ch10-Global Supply Chain - Cadena de Suministro.pdf
 
System Simulation and Modelling with types and Event Scheduling
System Simulation and Modelling with types and Event SchedulingSystem Simulation and Modelling with types and Event Scheduling
System Simulation and Modelling with types and Event Scheduling
 

GopherFest 2017 - Adding Context to NATS

  • 1.   Adding Context to Waldemar Quevedo / GopherFest 2017 @wallyqs 1 . 1
  • 2. Waldemar Quevedo / So!ware Developer at Development of the Apcera Platform NATS client maintainer (Ruby, Python) Using NATS since 2012 Speaking at GopherCon 2017 :D ABOUT @wallyqs Apcera 2 . 1
  • 3. ABOUT THIS TALK Quick intro to the NATS project What is Context? When to use it? How we added Context support to the NATS client What can we do with Context and NATS together 3 . 1
  • 4. Short intro to the NATS project… ! ! ! (for context) 4 . 1
  • 5. WHAT IS NATS? High Performance Messaging System Open Source, MIT License First written in in 2010 Rewritten in in 2012 Used in production for years at CloudFoundry, Apcera Platform On Github: Website: Ruby Go https://github.com/nats-io http://nats.io/ 5 . 1
  • 6. WHAT IS NATS? Fast, Simple & Resilient Minimal feature set Pure PubSub (no message persistence*) at-most-once delivery TCP/IP based under a basic plain text protocol (Payload is opaque to protocol)  * see project for at-least once deliveryNATS Streaming 6 . 1
  • 7. WHAT IS NATS USEFUL FOR? Useful to build control planes for microservices Supports <1:1, 1:N> types of communication Low Latency Request/Response Load balancing via Distribution Queues Great Throughput Above 10M messages per/sec for small payloads Max payload is 1MB by default 7 . 1
  • 9. Publishing API for 1:N communication nc, err := nats.Connect("nats://demo.nats.io:4222") if err != nil { log.Fatalf("Failed to connect: %sn", err) } nc.Subscribe("hello", func(m *nats.Msg) { log.Printf("Received message: %sn", string(m.Data)) }) // Broadcast message to all subscribed to 'hello' err := nc.Publish("hello", []byte("world")) if err != nil { log.Printf("Error publishing payload: %sn", err) } 9 . 1
  • 10. Request/Response API for 1:1 communication nc, err := nats.Connect("nats://demo.nats.io:4222") if err != nil { log.Fatalf("Failed to connect: %sn", err) } // Receive requests on the 'help' subject... nc.Subscribe("help", func(m *nats.Msg) { log.Printf("Received message: %sn", string(m.Data)) nc.Publish(m.Reply, []byte("ok can help")) }) // Wait for 2 seconds for response or give up result, err := nc.Request("help", []byte("please"), 2*time.Second) if err != nil { log.Printf("Error receiving response: %sn", err) } else { log.Printf("Result: %vn", string(result.Data)) } 10 . 1
  • 11. "❗"❗ Request/Response API takes a timeout before giving up, blocking until getting either a response or an error. result, err := nc.Request("help", []byte("please"), 2*time.Second) if err != nil { log.Printf("Error receiving response: %sn", err) } 11 . 1
  • 12. Shortcoming: there is no way to cancel the request! Could this be improved somehow? result, err := nc.Request("help", []byte("please"), 2*time.Second) if err != nil { log.Printf("Error receiving response: %sn", err) } 12 . 1
  • 13. Cancellation in Golang: Background The Done() channel https://blog.golang.org/pipelines 13 . 1
  • 14. Cancellation in Golang: Background The Context interface https://blog.golang.org/context 14 . 1
  • 15. The context package Since Go 1.7, included in standard library ✅ import "context" 15 . 1
  • 16. Current status Now many library authors are looking into adopting! % % % (GH query) Add context.Context extension:go state:open 16 . 1
  • 18. Standard library continuously adopting Context too. ■ net ■ net/http ■ database/sql func (d *Dialer) DialContext(ctx context.Context, network, address string) func (r *Request) WithContext(ctx context.Context) *Request func (db *DB) BeginTx(ctx context.Context, opts *TxOptions) (*Tx, error) 18 . 1
  • 19. TIP If it is a blocking call in a library, it will probably benefit from adding context.Context support soon. 19 . 1
  • 20. Ok, so how exactly is Context used? 20 . 1
  • 21. The Context toolkit type Context interface { Deadline() (deadline time.Time, ok bool) Done() <-chan struct{} Err() error Value(key interface{}) interface{} } type Context func Background() Context func TODO() Context func WithCancel(parent Context) (ctx Context, cancel CancelFunc) func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) func WithValue(parent Context, key, val interface{}) Context 21 . 1
  • 22. HTTP Example req, _ := http.NewRequest("GET", "http://demo.nats.io:8222/varz", nil) // Parent context ctx := context.Background() // Timeout context ctx, cancel := context.WithTimeout(ctx, 500*time.Millisecond) // Must always call the cancellation function! defer cancel() // Wrap request with the timeout context req = req.WithContext(ctx) result, err := http.DefaultClient.Do(req) if err != nil { log.Fatalf("Error: %sn", err) } 22 . 1
  • 23. 2 types of errors: ■ context.DeadlineExceeded (← net.Error) ■ context.Canceled Error: Get http://demo.nats.io:8222/varz: context deadline exceeded exit status 1 Error: Get http://demo.nats.io:8222/varz: context canceled exit status 1 23 . 1
  • 24. Cool! ⭐ Now let's add support for Context in the NATS client. 24 . 1
  • 25. What is a NATS Request? Essentially, it waits for this to happen in the network: # --> Request SUB _INBOX.ioL1Ws5aZZf5fyeF6sAdjw 2 UNSUB 2 1 PUB help _INBOX.ioL1Ws5aZZf5fyeF6sAdjw 6 please # <-- Response MSG _INBOX.ioL1Ws5aZZf5fyeF6sAdjw 2 11 ok can help 25 . 1
  • 26. What is a NATS Request? Request API: Syntactic sugar for this under the hood: result, err := nc.Request("help", []byte("please"), 2*time.Second) // Ephemeral subscription for request inbox := NewInbox() s, _ := nc.SubscribeSync(inbox) // Expect single response s.AutoUnsubscribe(1) defer s.Unsubscribe() // Announce request and reply inbox nc.PublishRequest("help", inbox, []byte("please")) // Wait for reply (*blocks here*) msg, _ := s.NextMsg(timeout) 26 . 1
  • 27. Adding context to NATS Requests First step, add new context aware API for the subscriptions to yield the next message or give up if context is done. // Classic func (s *Subscription) NextMsg(timeout time.Duration) (*Msg, error) // Context Aware API func (s *Subscription) NextMsgWithContext(ctx context.Context) (*Msg, error) 27 . 1
  • 28. (Just in case) To avoid breaking previous compatibility, add new functionality into a context.go file and add build tag to only support above Go17. // Copyright 2012-2017 Apcera Inc. All rights reserved. // +build go1.7 // A Go client for the NATS messaging system (https://nats.io). package nats import ( "context" ) 28 . 1
  • 29. Enhancing NextMsg with Context capabilities Without Context (code was simplified): func (s *Subscription) NextMsg(timeout time.Duration) (*Msg, error) { // Subscription channel over which we receive messages mch := s.mch var ok bool var msg *Msg t := time.NewTimer(timeout) // defer t.Stop() // Wait to receive message... select { case msg, ok = <-mch: if !ok { return nil, ErrConnectionClosed } case <-t.C: ' // ...or timer to expire return nil, ErrTimeout } return msg, nil 29 . 1
  • 30. First pass How about making Subscription context aware? // A Subscription represents interest in a given subject. type Subscription struct { // context used along with the subscription. ctx cntxt // ... func (s *Subscription) NextMsgWithContext(ctx context.Context) (*Msg, error) { // Call NextMsg from subscription but disabling the timeout // as we rely on the context for the cancellation instead. s.SetContext(ctx) msg, err := s.NextMsg(0) if err != nil { select { case <-ctx.Done(): return nil, ctx.Err() default: } } 30 . 1
  • 31. net/http uses this style type Request struct { // ctx is either the client or server context. It should only // be modified via copying the whole Request using WithContext. // It is unexported to prevent people from using Context wrong // and mutating the contexts held by callers of the same request. ctx context.Context } // WithContext returns a shallow copy of r with its context changed // to ctx. The provided ctx must be non-nil. func (r *Request) WithContext(ctx context.Context) *Request { if ctx == nil { panic("nil context") } r2 := new(Request) *r2 = *r r2.ctx = ctx return r2 } 31 . 1
  • 32. ❌ style not recommended 32 . 1
  • 33. Enhancing NextMsg with Context capabilities Without Context (code was simplified): func (s *Subscription) NextMsg(timeout time.Duration) (*Msg, error) { // Subscription channel over which we receive messages mch := s.mch var ok bool var msg *Msg t := time.NewTimer(timeout) // defer t.Stop() // Wait to receive message... select { case msg, ok = <-mch: if !ok { return nil, ErrConnectionClosed } case <-t.C: ' // ...or timer to expire return nil, ErrTimeout } return msg, nil 33 . 1
  • 34. Enhancing NextMsg with Context capabilities With Context: func (s *Subscription) NextMsgWithContext(ctx context.Context) (*Msg, error) { // Subscription channel over which we receive messages mch := s.mch var ok bool var msg *Msg // Wait to receive message... select { case msg, ok = <-mch: if !ok { return nil, ErrConnectionClosed } case <-ctx.Done(): ' // ...or Context to be done return nil, ctx.Err() } return msg, nil 34 . 1
  • 35. Learning from the standard library panic in case nil is passed? func (r *Request) WithContext(ctx context.Context) *Request { if ctx == nil { panic("nil context") } func (d *Dialer) DialContext(ctx context.Context, network, address string) (Conn, error) if ctx == nil { panic("nil context") } func CommandContext(ctx context.Context, name string, arg ...string) *Cmd { if ctx == nil { panic("nil Context") } 35 . 1
  • 36. Learning from the standard library panic is not common in the client library so we've added custom error for now instead func (s *Subscription) NextMsgWithContext(ctx context.Context) (*Msg, error) { if ctx == nil { return nil, ErrInvalidContext } 36 . 1
  • 37. Once we have NextMsgWithContext, we can build on it to add support for RequestWithContext func (nc *Conn) RequestWithContext(ctx context.Context, subj string, data []byte) ( *Msg, error, ) { // Ephemeral subscription for request inbox := NewInbox() s, _ := nc.SubscribeSync(inbox) // Expect single response s.AutoUnsubscribe(1) defer s.Unsubscribe() // Announce request and reply inbox nc.PublishRequest(subj, inbox, data)) // Wait for reply or context to be done return s.NextMsgWithContext(ctx) 37 . 1
  • 38. And that's it! We now have context.Context support ✌ 38 . 1
  • 39. NATS Request Example nc, _ := nats.Connect("nats://demo.nats.io:4222") nc.Subscribe("help", func(m *nats.Msg) { log.Printf("Received message: %sn", string(m.Data)) nc.Publish(m.Reply, []byte("ok can help")) }) // Parent context ctx := context.Background() ctx, cancel := context.WithTimeout(ctx, 2*time.Second) defer cancel() // Blocks until receiving request or context is done result, err := nc.RequestWithContext(ctx, "help", []byte("please")) if err != nil { log.Printf("Error receiving response: %sn", err) } else { log.Printf("Result: %vn", string(result.Data)) } 39 . 1
  • 40. Cool feature: Cancellation propagation Start from a parent context and chain the rest Opens the door for more advanced use cases without affecting readability too much. context.Background() !"" context.WithDeadline(...) !"" context.WithTimeout(...) 40 . 1
  • 41. Advanced usage with cancellation Example: Probe Request Goal: Gather as many messages as we can within 1s or until we have been idle without receiving replies for 250ms 41 . 1
  • 42. Expressed in terms of Context // Parent context ctx := context.Background() // Probing context with hard deadline to 1s ctx, done := context.WithTimeout(ctx, 1*time.Second) defer done() // must be called always // Probe deadline will be expanded as we gather replies timer := time.AfterFunc(250*time.Millisecond, func() { done() }) // ↑ (timer will be reset once a message is received) 42 . 1
  • 43. Expressed in terms of Context (cont'd) inbox := nats.NewInbox() sub, _ := nc.SubscribeSync(inbox) defer sub.Unsubscribe() start := time.Now() nc.PublishRequest("help", inbox, []byte("please help!")) replies := make([]*Msg, 0) for { // Receive as many messages as we can in 1s or until we stop // receiving new messages for over 250ms. result, err := sub.NextMsgWithContext(ctx) if err != nil { break } replies = append(replies, result) timer.Reset(250 * time.Millisecond) ' // reset timer! * } log.Printf("Received %d messages in %.3f seconds", len(replies), time.Since(start).Secon 43 . 1
  • 44. Expressed in terms of Context (cont'd) nc.Subscribe("help", func(m *nats.Msg) { log.Printf("Received help request: %sn", string(m.Data)) for i := 0; i < 100; i++ { // Starts to increase latency after a couple of requests if i >= 3 { time.Sleep(300 * time.Millisecond) } nc.Publish(m.Reply, []byte("ok can help")) log.Printf("Replied to help request (times=%d)n", i) time.Sleep(100 * time.Millisecond) } }) 44 . 1
  • 45. We could do a pretty advanced usage of the NATS library without writing a single select or more goroutines! 45 . 1
  • 46. CONCLUSIONS If a call blocks in your library, it will probably eventually require context.Context support. Some refactoring might be involved… Catchup with the ecosystem! context.Context based code composes nicely so makes up for very readable code Always call the cancellation function to avoid leaking resources! + 46 . 1