Changeset 449 in code for trunk/server.go


Ignore:
Timestamp:
Feb 9, 2021, 4:34:46 PM (4 years ago)
Author:
contact
Message:

Add support for graceful shutdown

Closes: https://todo.sr.ht/~emersion/soju/45

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/server.go

    r409 r449  
    66        "net"
    77        "net/http"
     8        "strings"
    89        "sync"
    910        "sync/atomic"
     
    5556        Identd         *Identd // can be nil
    5657
    57         db *DB
    58 
    59         lock  sync.Mutex
    60         users map[string]*user
     58        db     *DB
     59        stopWG sync.WaitGroup
     60
     61        lock      sync.Mutex
     62        listeners map[net.Listener]struct{}
     63        users     map[string]*user
    6164}
    6265
     
    6568                Logger:       log.New(log.Writer(), "", log.LstdFlags),
    6669                HistoryLimit: 1000,
     70                db:           db,
     71                listeners:    make(map[net.Listener]struct{}),
    6772                users:        make(map[string]*user),
    68                 db:           db,
    6973        }
    7074}
     
    7478}
    7579
    76 func (s *Server) Run() error {
     80func (s *Server) Start() error {
    7781        users, err := s.db.ListUsers()
    7882        if err != nil {
     
    8690        s.lock.Unlock()
    8791
    88         select {}
     92        return nil
     93}
     94
     95func (s *Server) Shutdown() {
     96        s.lock.Lock()
     97        for ln := range s.listeners {
     98                if err := ln.Close(); err != nil {
     99                        s.Logger.Printf("failed to stop listener: %v", err)
     100                }
     101        }
     102        for _, u := range s.users {
     103                u.events <- eventStop{}
     104        }
     105        s.lock.Unlock()
     106
     107        s.stopWG.Wait()
    89108}
    90109
     
    117136        s.users[u.Username] = u
    118137
     138        s.stopWG.Add(1)
     139
    119140        go func() {
    120141                u.run()
     
    123144                delete(s.users, u.Username)
    124145                s.lock.Unlock()
     146
     147                s.stopWG.Done()
    125148        }()
    126149
     
    146169
    147170func (s *Server) Serve(ln net.Listener) error {
     171        s.lock.Lock()
     172        s.listeners[ln] = struct{}{}
     173        s.lock.Unlock()
     174
     175        s.stopWG.Add(1)
     176
     177        defer func() {
     178                s.lock.Lock()
     179                delete(s.listeners, ln)
     180                s.lock.Unlock()
     181
     182                s.stopWG.Done()
     183        }()
     184
    148185        for {
    149186                conn, err := ln.Accept()
    150                 if err != nil {
     187                // TODO: use net.ErrClosed when available
     188                if err != nil && strings.Contains(err.Error(), "use of closed network connection") {
     189                        return nil
     190                } else if err != nil {
    151191                        return fmt.Errorf("failed to accept connection: %v", err)
    152192                }
Note: See TracChangeset for help on using the changeset viewer.