SlideShare a Scribd company logo
Job Queue in Golang
Bo-Yi Wu
2019.10.19
About me
• Software Engineer in Mediatek
• Member of Drone CI/CD Platform
• Member of Gitea Platform
• Member of Gin Golang Framework
• Maintain Some GitHub Actions Plugins.
• Teacher of Udemy Platform: Golang + Drone
Queue (Open Source)
RabbitMQ
NSQ
Why not
use Open Source?
Single Service
• Build in SQLite (LDAP, Job List)
• Build in Cache (LRU)
• Build for single binary
• No third-party dependency
Before talking about
Job Queue
Buffered
vs
Unbuffered
http://bit.ly/understand-channel
Goroutine
func main() {
go func() {
fmt.Println("GO GO GO")
}()
time.Sleep(1 * time.Second)
}
Unbuffered
make(chan bool)
Unbuffered Channel
func main() {
c := make(chan bool)
go func() {
fmt.Println("GO GO GO")
c <- true
}()
<-c
}
Unbuffered Channel
func main() {
c := make(chan bool)
go func() {
fmt.Println("GO GO GO")
c <- true
}()
<-c
}
Unbuffered Channel
func main() {
c := make(chan bool)
go func() {
fmt.Println("GO GO GO")
<-c
}()
c <- true
}
func main() {
c := make(chan bool)
go func() {
fmt.Println("GO GO GO")
c <- true
c <- true
}()
<-c
time.Sleep(1 * time.Second)
}
Unbuffered Channel
buffered
make(chan bool, 1)
Buffered channel
func main() {
c := make(chan bool, 1)
go func() {
fmt.Println("GO GO GO")
<-c
}()
c <- true
}
Buffered channel
func main() {
c := make(chan bool, 1)
go func() {
fmt.Println("GO GO GO")
<-c
}()
c <- true
}
Buffered channel
func main() {
c := make(chan bool, 1)
go func() {
fmt.Println("GO GO GO")
c <- true
}()
<-c
}
How to implement
Job Queue in Go
Sometimes you don’t need
A job queue
go process("job01")
func worker(jobChan <-chan Job) {
for job := range jobChan {
process(job)
}
}
// make a channel with a capacity of 1024.
jobChan := make(chan Job, 1024)
// start the worker
go worker(jobChan)
// enqueue a job
jobChan <- job
func worker(jobChan <-chan Job) {
for job := range jobChan {
process(job)
}
}
// make a channel with a capacity of 1024.
jobChan := make(chan Job, 1024)
// start the worker
go worker(jobChan)
// enqueue a job
jobChan <- job
Block if there already are 1024 jobs
jobChan := make(chan Job, 1024)
Enqueue without blocking
func Enqueue(job Job, jobChan chan<- Job) bool {
select {
case jobChan <- job:
return true
default:
return false
}
}
if !Enqueue(job, job100) {
Error(
http.StatusServiceUnavailable,
"max capacity reached",
)
return
}
Stopping the worker?
func main() {
ch := make(chan int, 2)
go func() {
ch <- 1
ch <- 2
}()
for n := range ch {
fmt.Println(n)
}
}
func main() {
ch := make(chan int, 2)
go func() {
ch <- 1
ch <- 2
close(ch)
}()
for n := range ch {
fmt.Println(n)
}
}
func main() {
ch := make(chan int, 2)
go func() {
ch <- 1
ch <- 2
}()
go func() {
for n := range ch {
fmt.Println(n)
}
}()
time.Sleep(1 * time.Second)
}
Setup Consumer
type Consumer struct {
inputChan chan int
jobsChan chan int
}
const PoolSize = 2
func main() {
// create the consumer
consumer := Consumer{
inputChan: make(chan int, 1),
jobsChan: make(chan int, PoolSize),
}
}
func (c *Consumer) queue(input int) {
fmt.Println("send input value:", input)
c.jobsChan <- input
}
func (c *Consumer) worker(num int) {
for job := range c.jobsChan {
fmt.Println("worker:", num, " job value:", job)
}
}
for i := 0; i < PoolSize; i++ {
go consumer.worker(i)
}
consumer.queue(1)
consumer.queue(2)
consumer.queue(3)
consumer.queue(4)
blocking by poll size = 2
Output (Poll Size = 2)
send input value: 1
send input value: 2
send input value: 3
worker: 0 job value: 1
send input value: 4
worker: 0 job value: 2
worker: 0 job value: 3
worker: 0 job value: 4
rewrite queue func
func (c *Consumer) queue(input int) bool {
fmt.Println("send input value:", input)
select {
case c.jobsChan <- input:
return true
default:
return false
}
}
Output (Poll Size = 2)
send input value: 1
send input value: 2
send input value: 3
send input value: 4
worker: 0 job value: 1
worker: 0 job value: 2
Shutdown with
Sigterm Handling
func WithContextFunc(ctx context.Context, f func()) context.Context {
ctx, cancel := context.WithCancel(ctx)
go func() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
defer signal.Stop(c)
select {
case <-ctx.Done():
case <-c:
f()
cancel()
}
}()
return ctx
}
func WithContextFunc(ctx context.Context, f func()) context.Context {
ctx, cancel := context.WithCancel(ctx)
go func() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
defer signal.Stop(c)
select {
case <-ctx.Done():
case <-c:
f()
cancel()
}
}()
return ctx
}
func (c Consumer) startConsumer(ctx context.Context) {
for {
select {
case job := <-c.inputChan:
if ctx.Err() != nil {
close(c.jobsChan)
return
}
c.jobsChan <- job
case <-ctx.Done():
close(c.jobsChan)
return
}
}
}
Cancel by ctx.Done() event
func (c *Consumer) worker(num int) {
for job := range c.jobsChan {
fmt.Println("worker:", num, " job value:", job)
}
}
Canceling Workers
without Context
cancelChan := make(chan struct{})
go worker(jobChan, cancelChan)
func worker(jobChan <-chan Job, cancelChan <-chan struct{}) {
for {
select {
case <-cancelChan:
return
case job := <-jobChan:
process(job)
}
}
}
// to cancel the worker, close the cancel channel
close(cancelChan)
Create a cancel channel
cancelChan := make(chan struct{})
go worker(jobChan, cancelChan)
func worker(jobChan <-chan Job, cancelChan <-chan struct{}) {
for {
select {
case <-cancelChan:
return
case job := <-jobChan:
process(job)
}
}
}
// to cancel the worker, close the cancel channel
close(cancelChan)
Create a cancel channel
close(cancelChan)
Graceful shutdown
with worker
sync.WaitGroup
wg := &sync.WaitGroup{}
wg.Add(numberOfWorkers)
// Start [PoolSize] workers
for i := 0; i < PoolSize; i++ {
go consumer.worker(i)
}
WaitGroup
WaitGroup
WaitGroup
WaitGroup
func (c Consumer) worker(wg *sync.WaitGroup) {
defer wg.Done()
for job := range c.jobsChan {
// handle the job event
}
}
Add WaitGroup
after Cancel Function
func WithContextFunc(ctx context.Context, f func()) context.Context {
ctx, cancel := context.WithCancel(ctx)
go func() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
defer signal.Stop(c)
select {
case <-ctx.Done():
case <-c:
cancel()
f()
}
}()
return ctx
}
Add WaitGroup after Cancel Function
wg := &sync.WaitGroup{}
wg.Add(numberOfWorkers)
ctx := signal.WithContextFunc(
context.Background(),
func() {
wg.Wait()
close(finishChan)
},
)
go consumer.startConsumer(ctx)
End of Program
select {
case <-finished:
case err := <-errChannel:
if err != nil {
return err
}
}
How to auto-scaling
build agent?
Communicate between
server and agent
Jobs Schema
r := e.Group("/rpc")
r.Use(rpc.Check())
{
r.POST("/v1/healthz", web.RPCHeartbeat)
r.POST("/v1/request", web.RPCRquest)
r.POST("/v1/accept", web.RPCAccept)
r.POST("/v1/details", web.RPCDetails)
r.POST("/v1/updateStatus", web.RPCUpdateStatus)
r.POST("/v1/upload", web.RPCUploadBytes)
r.POST("/v1/reset", web.RPCResetStatus)
}
Check RPC Secret
/rpc/v1/accept
Update jobs set version = (oldVersion + 1)
where machine = "fooBar" and version = oldVersion
Create multiple worker
if r.Capacity != 0 {
var g errgroup.Group
for i := 0; i < r.Capacity; i++ {
g.Go(func() error {
return r.start(ctx, 0)
})
time.Sleep(1 * time.Second)
}
return g.Wait()
}
Break for and select loop
func (r *Runner) start(ctx context.Context, id int64) error {
LOOP:
for {
select {
case <-ctx.Done():
return ctx.Err()
default:
r.poll(ctx, id)
if r.Capacity == 0 {
break LOOP
}
}
time.Sleep(1 * time.Second)
}
return nil
}
How to cancel the current Job?
Context with Cancel or Timeout
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
timeout, cancel := context.WithTimeout(ctx, 60*time.Minute)
defer cancel()
Job03 context
Context with Cancel or Timeout
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
timeout, cancel := context.WithTimeout(ctx, 60*time.Minute)
defer cancel()
Job03 context
Job05 context
Watch the Cancel event
go func() {
done, _ := r.Manager.Watch(ctx, id)
if done {
cancel()
}
}()
Handle cancel event on Server
subscribers: make(map[chan struct{}]int64),
cancelled: make(map[int64]time.Time),
User cancel running job
c.Lock()
c.cancelled[id] = time.Now().Add(time.Minute * 5)
for subscriber, build := range c.subscribers {
if id == build {
close(subscriber)
}
}
c.Unlock()
Agent subscribe the cancel event
for {
select {
case <-ctx.Done():
return false, ctx.Err()
case <-time.After(time.Minute):
c.Lock()
_, ok := c.cancelled[id]
c.Unlock()
if ok {
return true, nil
}
case <-subscriber:
return true, nil
}
}
case <-time.After(time.Minute):
c.Lock()
_, ok := c.cancelled[id]
c.Unlock()
if ok {
return true, nil
}
case <-time.After(time.Minute):
c.Lock()
_, ok := c.cancelled[id]
c.Unlock()
if ok {
return true, nil
}
1 Cancel
case <-time.After(time.Minute):
c.Lock()
_, ok := c.cancelled[id]
c.Unlock()
if ok {
return true, nil
}
1
2 Reconnect Server
Cancel
https://www.udemy.com/course/golang-fight/?couponCode=GOLANG201911
https://www.udemy.com/course/devops-oneday/?couponCode=DEVOPS201911
Any Question?

More Related Content

What's hot

What's hot (20)

Flask for cs students
Flask for cs studentsFlask for cs students
Flask for cs students
 
gRPC vs REST: let the battle begin!
gRPC vs REST: let the battle begin!gRPC vs REST: let the battle begin!
gRPC vs REST: let the battle begin!
 
NodeJS for Beginner
NodeJS for BeginnerNodeJS for Beginner
NodeJS for Beginner
 
Golang Channels
Golang ChannelsGolang Channels
Golang Channels
 
Javascript Module Patterns
Javascript Module PatternsJavascript Module Patterns
Javascript Module Patterns
 
JavaScript Event Loop
JavaScript Event LoopJavaScript Event Loop
JavaScript Event Loop
 
Functional programming with Java 8
Functional programming with Java 8Functional programming with Java 8
Functional programming with Java 8
 
Airflow presentation
Airflow presentationAirflow presentation
Airflow presentation
 
Interpreter, Compiler, JIT from scratch
Interpreter, Compiler, JIT from scratchInterpreter, Compiler, JIT from scratch
Interpreter, Compiler, JIT from scratch
 
gRPC: The Story of Microservices at Square
gRPC: The Story of Microservices at SquaregRPC: The Story of Microservices at Square
gRPC: The Story of Microservices at Square
 
Linux Networking Explained
Linux Networking ExplainedLinux Networking Explained
Linux Networking Explained
 
SRE Conf 2022 - 91APP 在 AWS 上的 SRE 實踐之路
SRE Conf 2022 - 91APP 在 AWS 上的 SRE 實踐之路SRE Conf 2022 - 91APP 在 AWS 上的 SRE 實踐之路
SRE Conf 2022 - 91APP 在 AWS 上的 SRE 實踐之路
 
Python as part of a production machine learning stack by Michael Manapat PyDa...
Python as part of a production machine learning stack by Michael Manapat PyDa...Python as part of a production machine learning stack by Michael Manapat PyDa...
Python as part of a production machine learning stack by Michael Manapat PyDa...
 
Build microservice with gRPC in golang
Build microservice with gRPC in golangBuild microservice with gRPC in golang
Build microservice with gRPC in golang
 
Java logging
Java loggingJava logging
Java logging
 
Nodejs presentation
Nodejs presentationNodejs presentation
Nodejs presentation
 
C# Async Await
C# Async AwaitC# Async Await
C# Async Await
 
Introduction to Go language
Introduction to Go languageIntroduction to Go language
Introduction to Go language
 
進擊的前端工程師:今天就用 JSON Server 自己打造 API 吧!
進擊的前端工程師:今天就用 JSON Server 自己打造 API 吧!進擊的前端工程師:今天就用 JSON Server 自己打造 API 吧!
進擊的前端工程師:今天就用 JSON Server 自己打造 API 吧!
 
Event Driven Systems with Spring Boot, Spring Cloud Streams and Kafka
Event Driven Systems with Spring Boot, Spring Cloud Streams and KafkaEvent Driven Systems with Spring Boot, Spring Cloud Streams and Kafka
Event Driven Systems with Spring Boot, Spring Cloud Streams and Kafka
 

Similar to Job Queue in Golang

Similar to Job Queue in Golang (20)

用 Go 語言打造多台機器 Scale 架構
用 Go 語言打造多台機器 Scale 架構用 Go 語言打造多台機器 Scale 架構
用 Go 語言打造多台機器 Scale 架構
 
GDG Devfest 2019 - Build go kit microservices at kubernetes with ease
GDG Devfest 2019 - Build go kit microservices at kubernetes with easeGDG Devfest 2019 - Build go kit microservices at kubernetes with ease
GDG Devfest 2019 - Build go kit microservices at kubernetes with ease
 
Think Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSThink Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJS
 
ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015
 
Finagle and Java Service Framework at Pinterest
Finagle and Java Service Framework at PinterestFinagle and Java Service Framework at Pinterest
Finagle and Java Service Framework at Pinterest
 
Writing Docker monitoring agent with Go
Writing Docker monitoring agent with GoWriting Docker monitoring agent with Go
Writing Docker monitoring agent with Go
 
Go Concurrency Patterns
Go Concurrency PatternsGo Concurrency Patterns
Go Concurrency Patterns
 
Presto anatomy
Presto anatomyPresto anatomy
Presto anatomy
 
Meetup talk: Readying your Go Webservice
Meetup talk: Readying your Go WebserviceMeetup talk: Readying your Go Webservice
Meetup talk: Readying your Go Webservice
 
Concurrency in go
Concurrency in goConcurrency in go
Concurrency in go
 
A deep dive into PEP-3156 and the new asyncio module
A deep dive into PEP-3156 and the new asyncio moduleA deep dive into PEP-3156 and the new asyncio module
A deep dive into PEP-3156 and the new asyncio module
 
Building and Incredible Machine with Pipelines and Generators in PHP (IPC Ber...
Building and Incredible Machine with Pipelines and Generators in PHP (IPC Ber...Building and Incredible Machine with Pipelines and Generators in PHP (IPC Ber...
Building and Incredible Machine with Pipelines and Generators in PHP (IPC Ber...
 
gRPC in Go
gRPC in GogRPC in Go
gRPC in Go
 
Things about Functional JavaScript
Things about Functional JavaScriptThings about Functional JavaScript
Things about Functional JavaScript
 
NDC Sydney 2019 - Async Demystified -- Karel Zikmund
NDC Sydney 2019 - Async Demystified -- Karel ZikmundNDC Sydney 2019 - Async Demystified -- Karel Zikmund
NDC Sydney 2019 - Async Demystified -- Karel Zikmund
 
.NET Core Summer event 2019 in Brno, CZ - Async demystified -- Karel Zikmund
.NET Core Summer event 2019 in Brno, CZ - Async demystified -- Karel Zikmund.NET Core Summer event 2019 in Brno, CZ - Async demystified -- Karel Zikmund
.NET Core Summer event 2019 in Brno, CZ - Async demystified -- Karel Zikmund
 
Extending Flux to Support Other Databases and Data Stores | Adam Anthony | In...
Extending Flux to Support Other Databases and Data Stores | Adam Anthony | In...Extending Flux to Support Other Databases and Data Stores | Adam Anthony | In...
Extending Flux to Support Other Databases and Data Stores | Adam Anthony | In...
 
Go ahead, make my day
Go ahead, make my dayGo ahead, make my day
Go ahead, make my day
 
От Java Threads к лямбдам, Андрей Родионов
От Java Threads к лямбдам, Андрей РодионовОт Java Threads к лямбдам, Андрей Родионов
От Java Threads к лямбдам, Андрей Родионов
 
Asynchronous programming with java script and node.js
Asynchronous programming with java script and node.jsAsynchronous programming with java script and node.js
Asynchronous programming with java script and node.js
 

More from Bo-Yi Wu

More from Bo-Yi Wu (20)

Drone CI/CD 自動化測試及部署
Drone CI/CD 自動化測試及部署Drone CI/CD 自動化測試及部署
Drone CI/CD 自動化測試及部署
 
Golang Project Layout and Practice
Golang Project Layout and PracticeGolang Project Layout and Practice
Golang Project Layout and Practice
 
Introduction to GitHub Actions
Introduction to GitHub ActionsIntroduction to GitHub Actions
Introduction to GitHub Actions
 
Drone 1.0 Feature
Drone 1.0 FeatureDrone 1.0 Feature
Drone 1.0 Feature
 
Drone CI/CD Platform
Drone CI/CD PlatformDrone CI/CD Platform
Drone CI/CD Platform
 
GraphQL IN Golang
GraphQL IN GolangGraphQL IN Golang
GraphQL IN Golang
 
Go 語言基礎簡介
Go 語言基礎簡介Go 語言基礎簡介
Go 語言基礎簡介
 
drone continuous Integration
drone continuous Integrationdrone continuous Integration
drone continuous Integration
 
Gorush: A push notification server written in Go
Gorush: A push notification server written in GoGorush: A push notification server written in Go
Gorush: A push notification server written in Go
 
用 Drone 打造 輕量級容器持續交付平台
用 Drone 打造輕量級容器持續交付平台用 Drone 打造輕量級容器持續交付平台
用 Drone 打造 輕量級容器持續交付平台
 
用 Go 語言 打造微服務架構
用 Go 語言打造微服務架構用 Go 語言打造微服務架構
用 Go 語言 打造微服務架構
 
Introduction to Gitea with Drone
Introduction to Gitea with DroneIntroduction to Gitea with Drone
Introduction to Gitea with Drone
 
運用 Docker 整合 Laravel 提升團隊開發效率
運用 Docker 整合 Laravel 提升團隊開發效率運用 Docker 整合 Laravel 提升團隊開發效率
運用 Docker 整合 Laravel 提升團隊開發效率
 
用 Go 語言實戰 Push Notification 服務
用 Go 語言實戰 Push Notification 服務用 Go 語言實戰 Push Notification 服務
用 Go 語言實戰 Push Notification 服務
 
用 Go 語言打造 DevOps Bot
用 Go 語言打造 DevOps Bot用 Go 語言打造 DevOps Bot
用 Go 語言打造 DevOps Bot
 
A painless self-hosted Git service: Gitea
A painless self-hosted Git service: GiteaA painless self-hosted Git service: Gitea
A painless self-hosted Git service: Gitea
 
Write microservice in golang
Write microservice in golangWrite microservice in golang
Write microservice in golang
 
用 Docker 改善團隊合作模式
用 Docker 改善團隊合作模式用 Docker 改善團隊合作模式
用 Docker 改善團隊合作模式
 
Git flow 與團隊合作
Git flow 與團隊合作Git flow 與團隊合作
Git flow 與團隊合作
 
PHP & JavaScript & CSS Coding style
PHP & JavaScript & CSS Coding stylePHP & JavaScript & CSS Coding style
PHP & JavaScript & CSS Coding style
 

Recently uploaded

Essentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with ParametersEssentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with Parameters
Safe Software
 
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo DiehlFuture Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
Peter Udo Diehl
 

Recently uploaded (20)

Essentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with ParametersEssentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with Parameters
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
 
10 Differences between Sales Cloud and CPQ, Blanka Doktorová
10 Differences between Sales Cloud and CPQ, Blanka Doktorová10 Differences between Sales Cloud and CPQ, Blanka Doktorová
10 Differences between Sales Cloud and CPQ, Blanka Doktorová
 
Behind the Scenes From the Manager's Chair: Decoding the Secrets of Successfu...
Behind the Scenes From the Manager's Chair: Decoding the Secrets of Successfu...Behind the Scenes From the Manager's Chair: Decoding the Secrets of Successfu...
Behind the Scenes From the Manager's Chair: Decoding the Secrets of Successfu...
 
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
 
Unpacking Value Delivery - Agile Oxford Meetup - May 2024.pptx
Unpacking Value Delivery - Agile Oxford Meetup - May 2024.pptxUnpacking Value Delivery - Agile Oxford Meetup - May 2024.pptx
Unpacking Value Delivery - Agile Oxford Meetup - May 2024.pptx
 
ODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User GroupODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User Group
 
"Impact of front-end architecture on development cost", Viktor Turskyi
"Impact of front-end architecture on development cost", Viktor Turskyi"Impact of front-end architecture on development cost", Viktor Turskyi
"Impact of front-end architecture on development cost", Viktor Turskyi
 
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptxIOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
 
Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and Grafana
 
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo DiehlFuture Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
 
UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3
 
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
 
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...
 
UiPath Test Automation using UiPath Test Suite series, part 1
UiPath Test Automation using UiPath Test Suite series, part 1UiPath Test Automation using UiPath Test Suite series, part 1
UiPath Test Automation using UiPath Test Suite series, part 1
 
Exploring UiPath Orchestrator API: updates and limits in 2024 🚀
Exploring UiPath Orchestrator API: updates and limits in 2024 🚀Exploring UiPath Orchestrator API: updates and limits in 2024 🚀
Exploring UiPath Orchestrator API: updates and limits in 2024 🚀
 
AI revolution and Salesforce, Jiří Karpíšek
AI revolution and Salesforce, Jiří KarpíšekAI revolution and Salesforce, Jiří Karpíšek
AI revolution and Salesforce, Jiří Karpíšek
 
Free and Effective: Making Flows Publicly Accessible, Yumi Ibrahimzade
Free and Effective: Making Flows Publicly Accessible, Yumi IbrahimzadeFree and Effective: Making Flows Publicly Accessible, Yumi Ibrahimzade
Free and Effective: Making Flows Publicly Accessible, Yumi Ibrahimzade
 

Job Queue in Golang