Take the required arguments and publish the given command.
        Arguments:
            tgt:
                The tgt is a regex or a glob used to match up the ids on
                the minions. Salt works by always publishing every command
                to all of the minions and then the minions determine if
                the command is for them based on the tgt value.
            fun:
                The function name to be called on the remote host(s), this
                must be a string in the format "<modulename>.<function name>"
            arg:
                The arg option needs to be a tuple of arguments to pass
                to the calling function, if left blank
        Returns:
            jid:
                A string, as returned by the publisher, which is the job
                id, this will inform the client where to get the job results
            minions:
                A set, the targets that the tgt passed should match.

def pub_async(self,
                  tgt,
                  fun,
                  arg=(),
                  tgt_type='glob',
                  ret='',
                  jid='',
                  timeout=5,
                  io_loop=None,
                  listen=True,
                  **kwargs):
        '''
        Take the required arguments and publish the given command.
        Arguments:
            tgt:
                The tgt is a regex or a glob used to match up the ids on
                the minions. Salt works by always publishing every command
                to all of the minions and then the minions determine if
                the command is for them based on the tgt value.
            fun:
                The function name to be called on the remote host(s), this
                must be a string in the format "<modulename>.<function name>"
            arg:
                The arg option needs to be a tuple of arguments to pass
                to the calling function, if left blank
        Returns:
            jid:
                A string, as returned by the publisher, which is the job
                id, this will inform the client where to get the job results
            minions:
                A set, the targets that the tgt passed should match.
        '''
        # Make sure the publisher is running by checking the unix socket
        if (self.opts.get('ipc_mode', '') != 'tcp' and
                not os.path.exists(os.path.join(self.opts['sock_dir'],
                'publish_pull.ipc'))):
            log.error(
                'Unable to connect to the salt master publisher at %s',
                self.opts['sock_dir']
            )
            raise SaltClientError

        payload_kwargs = self._prep_pub(
                tgt,
                fun,
                arg,
                tgt_type,
                ret,
                jid,
                timeout,
                **kwargs)

        master_uri = 'tcp://' + salt.utils.zeromq.ip_bracket(self.opts['interface']) + \
                     ':' + six.text_type(self.opts['ret_port'])
        channel = salt.transport.client.AsyncReqChannel.factory(self.opts,
                                                                io_loop=io_loop,
                                                                crypt='clear',
                                                                master_uri=master_uri)

        try:
            # Ensure that the event subscriber is connected.
            # If not, we won't get a response, so error out
            if listen and not self.event.connect_pub(timeout=timeout):
                raise SaltReqTimeoutError()
            payload = yield channel.send(payload_kwargs, timeout=timeout)
        except SaltReqTimeoutError:
            raise SaltReqTimeoutError(
                'Salt request timed out. The master is not responding. You '
                'may need to run your command with `--async` in order to '
                'bypass the congested event bus. With `--async`, the CLI tool '
                'will print the job id (jid) and exit immediately without '
                'listening for responses. You can then use '
                '`salt-run jobs.lookup_jid` to look up the results of the job '
                'in the job cache later.'
            )

        if not payload:
            # The master key could have changed out from under us! Regen
            # and try again if the key has changed
            key = self.__read_master_key()
            if key == self.key:
                raise tornado.gen.Return(payload)
            self.key = key
            payload_kwargs['key'] = self.key
            payload = yield channel.send(payload_kwargs)

        error = payload.pop('error', None)
        if error is not None:
            if isinstance(error, dict):
                err_name = error.get('name', '')
                err_msg = error.get('message', '')
                if err_name == 'AuthenticationError':
                    raise AuthenticationError(err_msg)
                elif err_name == 'AuthorizationError':
                    raise AuthorizationError(err_msg)

            raise PublishError(error)

        if not payload:
            raise tornado.gen.Return(payload)

        # We have the payload, let's get rid of the channel fast(GC'ed faster)
        channel.close()

        raise tornado.gen.Return({'jid': payload['load']['jid'],
                                  'minions': payload['load']['minions']})