Skip to content

[Pub/Sub] Add a bare Subscriber factory to Client #3369

Closed

Description

@kir-titievsky

Current Pub / Sub API requires a topic to create a subscription. This is unnecessary and cumbersome. It is also not feasible for some use cases: some users will only be given a subscription resource name to work with and not know the topic.

Current API:

from google.cloud import pubsub

client = pubsub.Client()
topic = client.topic(topic_name)
subscription = topic.subscription(sub_name)

Target:

subscription = client.subscription(sub_name)

Activity

  1. kir-titievsky commented on May 4, 2017

    @kir-titievsky
    Author
  2. dhermes commented on May 4, 2017

    @dhermes
    Contributor

    @kir-titievsky

    • FWIW, the behavior you want can already be accomplished (though not with a Client.subscription factory)

      from google.cloud import pubsub
      
      client = pubsub.Client()
      subscription = pubsub.Subscription(name, client=client)
    • RE: "only be given a subscription resource name to work with and not know the topic." Won't the topic be embedded in the subscription resource name?

  3. changed the title [-]Create subscriber client without a topic client[/-] [+][Pub/Sub] Add a bare Subscriber factory to Client[/+] on May 4, 2017
  4. self-assigned this
    on May 4, 2017
  5. dhermes commented on May 4, 2017

    @dhermes
    Contributor

    @kir-titievsky In our current implementation, a subscription with self.topic set to None will not be able to call Subscription.create() (there may be other methods that require a topic to be set on a Subscription but none that I can tell).

    Can you help me understand when a Subscription should have a Topic and when it doesn't matter? Also, can you give an example of a "a subscription resource name to work with and not know the topic"?

    Update: I see now

    screenshot from 2017-05-04 11-28-10

    Thanks

  6. kir-titievsky commented on May 4, 2017

    @kir-titievsky
    Author

    @dhermes Thank you for the prompt consideration! Good points. I did not consider the pubsub.Topic() and pubsub.Subscription() factories since they are not used in the documentation examples. We can fix that bit.

    That said, this still seems really not super great:

    1. There is an asymmetry here: pubsub.Client().topic() but a subscription but a subscription as pubsub.Client().topic().subscription()?
    2. You could argue that pubsub.Subscription() and pubsub.Topic() are the right way to create these, but both of these factories take a client as an argument. So you still have to do:
    client = pubsub.Client()
    subscription = pubsub.Subscription(sub_name, client=client) 

    Which would have been at least consistent, but we provide a much more comfortable interface for the topic: topic = pubsub.Client().topic() which leads me to expect the same for a subscription and also ask why would there be two separate interfaces for creating a subscription (or a topic) one of which is mildly (the pubsub.Topic(name, client=pubsub.Client()) and the other is inconsistent between Topic and Subscriber. The way this was solved in Java is to have separate data and admin classes (Subscriber and SubscriberAdmin). Perhaps a better thing to do is to say that Client() holds all admin operations, like list_topic() and list_subscription() as well as factories for creating subscribers and topics.

    Won't the topic be embedded in the subscription resource name?

    True. This is not an issue of keeping the topic name from the user. It's about not requiring the user to know the topic name in order to create a subscription in the first place.

  7. added a commit that references this issue on May 4, 2017
    7475da9
  8. dhermes commented on May 4, 2017

    @dhermes
    Contributor

    @kir-titievsky pubsub.Subscription and pubsub.Topic are not factories, they are just the classes (but they ARE part of the public interface).

    I sent #3370 to add a Subscription factory, so it should be all good?

  9. kir-titievsky commented on May 4, 2017

    @kir-titievsky
    Author

    In our current implementation, a subscription with self.topic set to None will not be able to call Subscription.create() (there may be other methods that require a topic to be set on a Subscription but none that I can tell).

    Right. I can see the logic there, since you always create a subscription to a topic. But in my mind the right solution is to have a Client().create_subscription(topic=topic_name, subscription_name) or Client().topic(topic_name).create_subscription(subscription_name).

    # current logic
    s = Subscription(topic_name, client=Client())
    if not s.exists(): 
        s.create()

    The alternative would be:

    if  not Client().subscription_exists():  # create subscription
        s = Subscription(subscription_name)  # always produces a fully working object

    or at least

    try:
        s = Subscription(subscription_name)
    except exceptions.NotFound:
        Client().topic(...).create_subscription(...)

    We are getting into matters of taste, I think.

    Can you help me understand when a Subscription should have a Topic and when it doesn't matter?

    The only use case I can think of is listing subscriptions to a given topic (rather than all subscriptions in the active project). This is, sort of, a convenience method. So the long form is:

    [i for i in Client().list_subscription() if i.topic_name = topic()]

    The possibly neater version is

    Client.topic().get_subscriptions()

    There are two distinct API methods.

    Also, can you give an example of a "a subscription resource name to work with and not know the topic"?

    If I want to give a third party developer in my project a minimum scope of access, I might give that person a subscription.pull role but not a topic.get permission. This way, the developer may access the data but not modify the access points. (see https://cloud.google.com/pubsub/docs/access_control)

  10. kir-titievsky commented on May 4, 2017

    @kir-titievsky
    Author

    @dhermes Wrote that last comment before seeing yours. Would you please give an example of how the usage changes with your PR?

  11. dhermes commented on May 4, 2017

    @dhermes
    Contributor

    @kir-titievsky

    The usage doesn't "change" (i.e. the PR is an additive change, so it adds something new). The newly enabled behavior is as you mapped out:

    subscription = client.subscription(sub_name)

    Let's discuss further on the PR?

  12. added a commit that references this issue on May 10, 2017
    3df8543
  13. dhermes commented on May 16, 2017

    @dhermes
    Contributor

    @kir-titievsky We can open a new issue if there are thing's you'd like to discuss?

    Some of your comments above indicate that you'd like a way for users to bundle object creation and a call to reload() with a single helper / method.

  14. kir-titievsky commented on May 16, 2017

    @kir-titievsky
    Author
  15. dhermes commented on May 16, 2017

    @dhermes
    Contributor

    👍

  16. added a commit that references this issue on Mar 2, 2026
    11c976f
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

api: pubsubIssues related to the Pub/Sub API.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions