github.com/qiuhoude/go-web@v0.0.0-20220223060959-ab545e78f20d/prepare/23_proto_actor/backpressure/main.go (about)

     1  package main
     2  
     3  import (
     4  	"log"
     5  	"sync/atomic"
     6  	"time"
     7  
     8  	"github.com/AsynkronIT/goconsole"
     9  	"github.com/AsynkronIT/protoactor-go/actor"
    10  	"github.com/AsynkronIT/protoactor-go/mailbox"
    11  )
    12  
    13  // sent to producer to request more work
    14  type requestMoreWork struct {
    15  	items int
    16  }
    17  type requestWorkBehavior struct {
    18  	tokens   int64
    19  	producer *actor.PID
    20  }
    21  
    22  func (m *requestWorkBehavior) MailboxStarted() {
    23  	m.requestMore()
    24  }
    25  func (m *requestWorkBehavior) MessagePosted(msg interface{}) {
    26  
    27  }
    28  func (m *requestWorkBehavior) MessageReceived(msg interface{}) {
    29  	atomic.AddInt64(&m.tokens, -1)
    30  	if m.tokens == 0 {
    31  		m.requestMore()
    32  	}
    33  }
    34  func (m *requestWorkBehavior) MailboxEmpty() {
    35  }
    36  
    37  func (m *requestWorkBehavior) requestMore() {
    38  	log.Println("Requesting more tokens")
    39  	m.tokens = 50
    40  	context.Send(m.producer, &requestMoreWork{items: 50})
    41  }
    42  
    43  type producer struct {
    44  	requestedWork int
    45  	worker        *actor.PID
    46  }
    47  
    48  func (p *producer) Receive(ctx actor.Context) {
    49  	switch msg := ctx.Message().(type) {
    50  	case *actor.Started:
    51  		// spawn our worker
    52  		workerProps := actor.PropsFromProducer(func() actor.Actor { return &worker{} }).
    53  			WithMailbox(mailbox.Bounded(30, &requestWorkBehavior{
    54  				producer: ctx.Self(),
    55  			}))
    56  		p.worker = ctx.Spawn(workerProps)
    57  	case *requestMoreWork:
    58  		p.requestedWork += msg.items
    59  		log.Println("Producer got a new work request")
    60  		ctx.Send(ctx.Self(), &produce{})
    61  	case *produce:
    62  		// produce more work
    63  		log.Println("Producer is producing work")
    64  		ctx.Send(p.worker, &work{})
    65  
    66  		// decrease our workload and tell ourselves to produce more work
    67  		if p.requestedWork > 0 {
    68  			p.requestedWork--
    69  			ctx.Send(ctx.Self(), &produce{})
    70  		}
    71  	}
    72  }
    73  
    74  type produce struct{}
    75  
    76  type worker struct {
    77  }
    78  
    79  func (w *worker) Receive(ctx actor.Context) {
    80  	switch msg := ctx.Message().(type) {
    81  	case *work:
    82  		log.Printf("Worker is working %v", msg)
    83  		time.Sleep(100 * time.Millisecond)
    84  	}
    85  }
    86  
    87  type work struct {
    88  }
    89  
    90  var context *actor.RootContext
    91  
    92  func main() {
    93  	context = actor.EmptyRootContext
    94  	producerProps := actor.PropsFromProducer(func() actor.Actor { return &producer{} })
    95  	context.Spawn(producerProps)
    96  
    97  	console.ReadLine()
    98  }