kombu transport 查找的处理

简单说明下kombu transport查找的处理,方便学习自定义broker的处理

Connection 处理

def __init__(self, hostname='localhost', userid=None,
             password=None, virtual_host=None, port=None, insist=False,
             ssl=False, transport=None, connect_timeout=5,
             transport_options=None, login_method=None, uri_prefix=None,
             heartbeat=0, failover_strategy='round-robin',
             alternates=None, **kwargs):
    alt = [] if alternates is None else alternates
    # have to spell the args out, just to get nice docstrings :(
    params = self._initial_params = {
        'hostname': hostname, 'userid': userid,
        'password': password, 'virtual_host': virtual_host,
        'port': port, 'insist': insist, 'ssl': ssl,
        'transport': transport, 'connect_timeout': connect_timeout,
        'login_method': login_method, 'heartbeat': heartbeat
    }

    if hostname and not isinstance(hostname, str):
        alt.extend(hostname)
        hostname = alt[0]
        params.update(hostname=hostname)
    if hostname:
        if ';' in hostname:
            alt = hostname.split(';') + alt
            hostname = alt[0]
            params.update(hostname=hostname)
        if '://' in hostname and '+' in hostname[:hostname.index('://')]:
            # e.g. sqla+mysql://root:masterkey@localhost/
            params['transport'], params['hostname'] = \
                hostname.split('+', 1)
            self.uri_prefix = params['transport']
        elif '://' in hostname:
            transport = transport or urlparse(hostname).scheme
            if not get_transport_cls(transport).can_parse_url:
                # we must parse the URL
                url_params = parse_url(hostname)
                params.update(
                    dictfilter(url_params),
                    hostname=url_params['hostname'],
                )

            params['transport'] = transport

    self._init_params(**params)

get_transport_cls 处理

def get_transport_cls(transport: str | None = None) -> str | None:
    """Get transport class by name.

    The transport string is the full path to a transport class, e.g.::

        "kombu.transport.pyamqp:Transport"

    If the name does not include `"."` (is not fully qualified),
    the alias table will be consulted.
    """
    if transport not in _transport_cache:
        # resolve_transport 此处会进行解析处理
        _transport_cache[transport] = resolve_transport(transport)
    return _transport_cache[transport]

resolve_transport 的处理

def resolve_transport(transport: str | None = None) -> str | None:
    """Get transport by name.

    Arguments:
    ---------
        transport (Union[str, type]): This can be either
            an actual transport class, or the fully qualified
            path to a transport class, or the alias of a transport.
    """
    if isinstance(transport, str):
        try:
            transport = TRANSPORT_ALIASES[transport]
        except KeyError:
            if '.' not in transport and ':' not in transport:
                from kombu.utils.text import fmatch_best
                alt = fmatch_best(transport, TRANSPORT_ALIASES)
                if alt:
                    raise KeyError(
                        'No such transport: {}.  Did you mean {}?'.format(
                            transport, alt))
                raise KeyError(f'No such transport: {transport}')
        else:
            if callable(transport):
                transport = transport()
        # symbol_by_name 比较有意思可以进行一个额外的检查处理,比如基于包格式的
        return symbol_by_name(transport)
    return transport

symbol_by_name 处理(可以支持类似proj.transports.MyTransport://localhost 格式的处理)

def symbol_by_name(name, aliases=None, imp=None, package=None,
                   sep='.', default=None, **kwargs):
    """Get symbol by qualified name.

    The name should be the full dot-separated path to the class::

        modulename.ClassName

    Example::

        celery.concurrency.processes.TaskPool
                                    ^- class name

    or using ':' to separate module and symbol::

        celery.concurrency.processes:TaskPool

    If `aliases` is provided, a dict containing short name/long name
    mappings, the name is looked up in the aliases first.

    Examples
    --------
        >>> symbol_by_name('celery.concurrency.processes.TaskPool')
        <class 'celery.concurrency.processes.TaskPool'>

        >>> symbol_by_name('default', {
        ...     'default': 'celery.concurrency.processes.TaskPool'})
        <class 'celery.concurrency.processes.TaskPool'>

        # Does not try to look up non-string names.
        >>> from celery.concurrency.processes import TaskPool
        >>> symbol_by_name(TaskPool) is TaskPool
        True
    """
    aliases = {} if not aliases else aliases
    if imp is None:
        imp = importlib.import_module

    if not isinstance(name, str):
        return name                                 # already a class

    name = aliases.get(name) or name
    sep = ':' if ':' in name else sep
    module_name, _, cls_name = name.rpartition(sep)
    if not module_name:
        cls_name, module_name = None, package if package else cls_name
    try:
        try:
            module = imp(module_name, package=package, **kwargs)
        except ValueError as exc:
            reraise(ValueError,
                    ValueError(f"Couldn't import {name!r}: {exc}"),
                    sys.exc_info()[2])
        return getattr(module, cls_name) if cls_name else module
    except (ImportError, AttributeError):
        if default is None:
            raise
    return default

说明

以上只是结合代码简单说明下kombu 对于transport 协议具体实现的查找处理,了解处理可以更好的学习内部处理

参考资料

https://github.com/celery/kombu/blob/5a88a28f31ab958072910d6f40f022296bea720c/kombu/connection.py

posted on 2025-03-09 08:00  荣锋亮  阅读(10)  评论(0)    收藏  举报

导航