mosquito / aio-pika

AMQP 0.9 client designed for asyncio and humans.
https://aio-pika.readthedocs.org/
Apache License 2.0
1.18k stars 186 forks source link

connect with url ignores all other parameters #551

Open ba1dr opened 1 year ago

ba1dr commented 1 year ago

This is related to both functions connect and connect_robust. Being called with parameters url and, say, client_properties the latter is not used.

The problem is in the make_url() function:

def make_url(
    url: Union[str, URL, None] = None,
    ...
) -> URL:
    if url is not None:
        if not isinstance(url, URL):
            return URL(url)
        return url
    ...

If the url is passed - all other parameters are ignored. In my case I store one connection string in the shared config file but different scripts (many of them) may set their own names (connection_name) upon connecting to the broker. I am not sure if this is correct to merge kwargs with the connection string (I'd prefer yes), but this is not good to just silently swallow and ignore the parameters. I'd suggest to at least raise an exception (or put a warning) if there is something except url is passed. The current behaviour was not obvious and I spent several hours googling and browsing the sources to find the root case.

mosquito commented 1 year ago

in this case connection name might be a part of the url, like ?name=my%20custom%20name

ba1dr commented 1 year ago

Yes, I got this after I found #301 . But it was not obvious at all that the parameter client_properties accepted, but silently ignored. If it threw an exception - I'd understood that faster. I am migrating my code from kombu and it allows to combine connection string with the additional parameters. In addition - these parameters are likely not passed to RabbitMQ directly along with hostname/password/etc, but extracted and sent separately, which makes it no sense to be sent only in connection string. Even aiormq library accepts client_properties in its connect() method, but we have no access to it through aio_pika.

mosquito commented 1 year ago

If you know how it's might be fixed, do not keep silence.

ba1dr commented 1 year ago

I see many ways to fix this, but this is you who could choose a decision.

  1. Ultimate solution. The most correct one as for me. To merge connection string with all the other parameters. To decompose url into the parts and overwrite parts with the parameters if passed. Can break backward compatibility for those who already uses the library but do not know about the current behaviour. Can bring new bugs as well.

  2. Partial solution. A bit ugly and not obvious either. To merge only query part of the url - to merge only client_properties or kwargs. Other parameters remain silently ignored. Makes not too much sense.

  3. "You're-doing-it-wrong" way of solution. At least clears further questions on the subject. We throw an exception if url is passed with anything else. Breaks backward compatibility. But you do not receive any more issues about missing connection_name.

  4. "tag: Known issue" way of solution. Quick'n' lazy. Like (3) but write a warning instead of exception.

mosquito commented 1 year ago

the MERGE implies CONFLICTS, what is source of truth? The URL should be updated by the params, or the params might replaced by the url parts?

ba1dr commented 1 year ago

Again, this is just a matter of definition. If you write in the docs that the parameters have more importance if passed - then this is it. I can see the scenario where the connection string is kept as a base for other parameters to be clarified later. Examples:

I am voting for the merge and resolve the conflicts in favor of additional parameters. Right now I have to write the sh*t like this in my code:

        if '?' in amqp_connstr:
            amqp_connstr += f'&name={quote(amqp_name)}'
        else:
            amqp_connstr += f'?name={quote(amqp_name)}'

Obviously this contains a mistake too - if the name has been already defined in the connection string - there is a conflict again. But I have no willing to implement a complete url parsing into that part of my code just to replace the connection name.