Go开源:Gores - Redis 的消息队列系统

k5135 8年前
   <h2>Gores</h2>    <p>An asynchronous job execution system based on Redis</p>    <h2>Installation</h2>    <p>Get the package</p>    <pre>  <code class="language-go">$ go get github.com/wang502/gores/gores</code></pre>    <p>Import the package</p>    <pre>  <code class="language-go">import "github.com/wang502/gores/gores"</code></pre>    <h2>Usage</h2>    <h3>Configuration</h3>    <p>Add a config.json in your project folder</p>    <pre>  <code class="language-go">{    "REDISURL": "127.0.0.1:6379",    "REDIS_PW": "mypassword",    "BLPOP_MAX_BLOCK_TIME" : 1,    "MAX_WORKERS": 2,    "Queues": ["queue1", "queue2"],    "DispatcherTimeout": 5,    "WorkerTimeout": 5  }</code></pre>    <ul>     <li><strong><em>REDISURL</em> </strong> : Redis server address. If you run in a local Redis, the dafault host is 127.0.0.1:6379</li>     <li><strong><em>REDIS_PW</em> </strong> : Redis password. If the password is not set, then password can be any string.</li>     <li><strong><em>BLPOP_MAX_BLOCK_TIME</em> </strong> : Blocking time when calling BLPOP command in Redis.</li>     <li><strong><em>MAX_WORKERS</em> </strong> : Maximum number of concurrent workers, each worker is a separate goroutine that execute specific task on the fetched item.</li>     <li><strong><em>Queues</em> </strong> : Array of queue names on Redis message broker.</li>     <li><strong><em>DispatcherTimeout</em> </strong> : Duration dispatcher will wait to dispatch new job before quitting.</li>     <li><strong><em>WorkerTimeout</em> </strong> : Duration worker will wait to process new job before quitting.</li>    </ul>    <p>Initialize config</p>    <pre>  <code class="language-go">configPath := flag.String("c", "config.json", "path to configuration file")  flag.Parse()  config, err := gores.InitConfig(*configPath)</code></pre>    <h3>Enqueue item to Redis queue</h3>    <p>An item is a Go map. It is required to have several keys:</p>    <ul>     <li><strong><em>Name</em> </strong> : name of the item to enqueue, items with different names are mapped to different tasks.</li>     <li><strong><em>Queue</em> </strong> : name of the queue you want to put the item in.</li>     <li><strong><em>Args</em> </strong> : the required arguments that you need in order for the workers to execute those tasks.</li>     <li><strong><em>Enqueue_timestamp</em> </strong> : the Unix timestamp of when the item is enqueued.</li>    </ul>    <pre>  <code class="language-go">resq := gores.NewResQ(config)  item := map[string]interface{}{    "Name": "Rectangle",    "Queue": "TestJob",    "Args": map[string]interface{}{                  "Length": 10,                  "Width": 10,            },    "Enqueue_timestamp": time.Now().Unix(),  }    err = resq.Enqueue(item)  if err != nil {      log.Fatalf("ERROR Enqueue item to ResQ")  }</code></pre>    <pre>  <code class="language-go">$ go run main.go -c ./config.json -o produce</code></pre>    <h3>Define tasks</h3>    <pre>  <code class="language-go">package tasks    // task for item with 'Name' = 'Rectangle'  // calculating the area of an rectangle by multiplying Length with Width  func CalculateArea(args map[string]interface{}) error {      var err error        length := args["Length"]      width := args["Width"]      if length == nil || width == nil {          err = errors.New("Map has no required attributes")          return err      }      fmt.Printf("The area is %d\n", int(length.(float64)) * int(width.(float64)))      return err  }</code></pre>    <h3>Launch workers to consume items and execute tasks</h3>    <pre>  <code class="language-go">tasks := map[string]interface{}{                "Item": tasks.PrintItem,                "Rectangle": tasks.CalculateArea,           }  gores.Launch(config, &tasks)</code></pre>    <pre>  <code class="language-go">$ go run main.go -c ./config.json -o consume</code></pre>    <p>The output will be:</p>    <pre>  <code class="language-go">The rectangle area is 100</code></pre>    <h3>Info about processed/failed job</h3>    <pre>  <code class="language-go">resq := gores.NewResQ(config)  if resq == nil {      log.Fatalf("resq is nil")  }  info := resq.Info()  for k, v := range info {      switch v.(type) {      case string:        fmt.Printf("%s : %s\n", k, v)      case int:        fmt.Printf("%s : %d\n", k, v)      case int64:        fmt.Printf("%s : %d\n", k, v)      }  }</code></pre>    <p>The output will be:</p>    <pre>  <code class="language-go">Gores Info:  queues : 2  workers : 0  failed : 0  host : 127.0.0.1:6379  pending : 0  processed : 1</code></pre>    <h2>Contribution</h2>    <p>Please feel free to suggest new features. Also open to pull request!</p>    <p> </p>    <p> </p>