code: func (d *Dispatcher) RegisterTask(prototype proto.Message, cb Handler, queue string, opts *taskqueue.RetryOptions) {
  	if queue == "" {
  		queue = "default" // default GAE task queue name, always exists
  	}
  
  	name := proto.MessageName(prototype)
  	if name == "" {
  		panic(fmt.Sprintf("unregistered proto message type %T", prototype))
  	}
  
  	d.mu.Lock()
  	defer d.mu.Unlock()
  
  	if _, ok := d.handlers[name]; ok {
  		panic(fmt.Sprintf("handler for %q has already been registered", name))
  	}
  
  	if d.handlers == nil {
  		d.handlers = make(map[string]handler)
  	}
  
  	d.handlers[name] = handler{
  		cb:        cb,
  		typeName:  name,
  		queue:     queue,
  		retryOpts: opts,
  	}
  }
docs: // RegisterTask tells the dispatcher that tasks of given proto type should be
  // handled by the given handler and routed through the given task queue.
  //
  // 'prototype' should be a pointer to some concrete proto message. It will be
  // used only for its type signature.
  //
  // Intended to be called during process startup. Panics if such message has
  // already been registered.