// lockForAction creates the action node in zookeeper, waits for the // queue lock, displays a nice error message if it cant get it func (zkts *Server) lockForAction(actionDir, contents string, timeout time.Duration, interrupted chan struct{}) (string, error) { // create the action path actionPath, err := zkts.zconn.Create(actionDir, contents, zookeeper.SEQUENCE|zookeeper.EPHEMERAL, zookeeper.WorldACL(zk.PERM_FILE)) if err != nil { return "", err } err = zk.ObtainQueueLock(zkts.zconn, actionPath, timeout, interrupted) if err != nil { var errToReturn error switch err { case zk.ErrInterrupted: errToReturn = topo.ErrInterrupted case zk.ErrTimeout: errToReturn = topo.ErrTimeout default: errToReturn = fmt.Errorf("failed to obtain action lock: %v %v", actionPath, err) } // Regardless of the reason, try to cleanup. log.Warningf("Failed to obtain action lock: %v", err) zkts.zconn.Delete(actionPath, -1) // Show the other actions in the directory dir := path.Dir(actionPath) children, _, err := zkts.zconn.Children(dir) if err != nil { log.Warningf("Failed to get children of %v: %v", dir, err) return "", errToReturn } if len(children) == 0 { log.Warningf("No other action running, you may just try again now.") return "", errToReturn } childPath := path.Join(dir, children[0]) data, _, err := zkts.zconn.Get(childPath) if err != nil { log.Warningf("Failed to get first action node %v (may have just ended): %v", childPath, err) return "", errToReturn } log.Warningf("------ Most likely blocking action: %v\n%v", childPath, data) return "", errToReturn } return actionPath, nil }
func cmdQlock(subFlags *flag.FlagSet, args []string) { var ( lockWaitTimeout = subFlags.Duration("lock-wait-timeout", 0, "wait for a lock for the specified duration") ) subFlags.Parse(args) zkPath := fixZkPath(subFlags.Arg(0)) sigRecv := make(chan os.Signal, 1) interrupted := make(chan struct{}) signal.Notify(sigRecv, os.Interrupt) go func() { <-sigRecv close(interrupted) }() if err := zk.ObtainQueueLock(zconn, zkPath, *lockWaitTimeout, interrupted); err != nil { log.Fatalf("qlock: error %v: %v", zkPath, err) } fmt.Printf("qlock: locked %v\n", zkPath) }