Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Application fails to start when using Pulsar binder in multi-binder scenario #3013

Open
onobc opened this issue Oct 2, 2024 · 5 comments
Open
Assignees

Comments

@onobc
Copy link
Contributor

onobc commented Oct 2, 2024

Scenario

A Spring Boot application using SCSt w/ Pulsar binder as input and Kafka binder as an output.

Problem

App fails to start w/ following message:

No qualifying bean of type 'org.springframework.pulsar.core.PulsarAdministration.

Expected Behavior

Application starts with Pulsar as input binder and Kafka as output binder.

Details

The reporting user followed this guide to configure the binders w/ the following yaml:

      binders:
        kafka:
          type: kafka
          (...)
        pulsar:
          type: pulsar
          environment:
            spring:
              cloud:
                stream:
                  pulsar:
                    binder:
                      config:
                        serviceUrl: pulsar://localhost:6650
                        adminUrl: http://localhost:8080

After deleting the environment property from pulsar binder config above, everything is fine, but it disables the possibility of additional configuration at this level.

Original report: https://stackoverflow.com/questions/79046248/springboot-spring-cloud-stream-pulsar-binder-startup-failed

@onobc onobc self-assigned this Oct 2, 2024
@Dagmara-K
Copy link

Issue observed for Springboot 3.3.2 + spring-cloud-stream 4.1.2, we tried also Springboot 3.2, 3.1 and 3.0, the same behaviour every time.

@onobc
Copy link
Contributor Author

onobc commented Oct 18, 2024

Background

The Pulsar binder currently relies on Spring Boot auto-configuration (PulsarAutoConfiguration) to provide the necessary components to communicate to/from Pulsar.
This works well when for a Spring Boot application with a single binder as the binder context shares the outer application context and gets access to all of the expected Pulsar auto-configured components.
However, the moment that we add another binder and set the environment property, we are telling SCSt to not use the outer application context and instead rely on its own configuration.

The above is more elegantly stated in Connecting to Multiple Systems.

In fact, you can remove the Kafka 2nd binder out of this equation and reproduce the error w/ this single Pulsar binder that is specifying the environment.

So why does this work for Rabbit and Kafka?

The reason is that the Rabbit|KafkaBinderConfiguration import a subset of their respective Spring Boot auto-configuration directly. I highlight subset because it is frowned upon to directly rely on Spring Boot auto-configuration classes as they are not considered public API.

We broke the direct dependence for Rabbit and Kafka a while back (here and here) which allowed us to include this subset of the auto-configuration for their binders.

This subset of configuration does not yet exist for Spring Pulsar so when we implemented the Pulsar binder we decided to keep it simple and support a single binder in a Spring Boot Spring Pulsar application.

Workarounds

However, until we break the dependence on the PulsarAutoConfiguration, there are workarounds to support multi-binders for Pulsar.

Note

For simplicity of this example, let's assume we want 2 Pulsar binders. Pulsar1 6650/8080 and Pulsar2 7750/9090.

Workaround 1

  1. Exclude the application's outer PulsarAutoConfiguration
  2. Then add the 2 binder entries, specifying spring.main.sources to include the auto-configuration on the environment entry.

The example above becomes:

spring:
  autoconfigure:
    exclude: org.springframework.boot.autoconfigure.pulsar.PulsarAutoConfiguration
  cloud:
    stream:
      binders:
        pulsar1:
          type: pulsar
          environment:
            spring:
              main.sources: org.springframework.boot.autoconfigure.pulsar.PulsarAutoConfiguration
              cloud:
                stream:
                  pulsar:
                    binder:
                      config:
                        serviceUrl: pulsar://localhost:6650
                        adminUrl: http://localhost:8080
        pulsar2:
          type: pulsar
          environment:
            spring:
              main.sources: org.springframework.boot.autoconfigure.pulsar.PulsarAutoConfiguration
              cloud:
                stream:
                  pulsar:
                    binder:
                      config:
                        serviceUrl: pulsar://localhost:7750
                        adminUrl: http://localhost:9090      

Workaround 2

  1. Create a binder entry for the 2nd binder, specifying spring.main.sources to include the auto-configuration and mark it as not a default candidate (this will make SCSt continue w/ the default binding process for binder 1 as it will think there is only 1 binder (described here).
  2. Then set the spring.cloud.stream.default-binder to the 1st binder (i.e. the pulsar binder and It will use the default Pulsar auto-configuration).

The example above becomes:

spring:
  cloud:
    stream:
      default-binder: pulsar
      binders:
        pulsar2:
          type: pulsar
          default-candidate: false
          environment:
            spring:
              main.sources: org.springframework.boot.autoconfigure.pulsar.PulsarAutoConfiguration
              cloud:
                stream:
                  pulsar:
                    binder:
                      config:
                        serviceUrl: pulsar://localhost:7750
                        adminUrl: http://localhost:9090      

Let us know once you give one of the above workarounds a try. Once we are done communicating on this issue I will close it and create an issue to break the dependence on the Pulsar auto-configuration (like we did previously for Kafka and Rabbit).

Thanks

@onobc onobc removed the bug label Oct 18, 2024
@onobc
Copy link
Contributor Author

onobc commented Oct 18, 2024

Note

I removed the bug label as this was known when we implemented the binder (I seemed to have amnesia on this topic until I spent about 45m digging into this issue and then it all came flooding back into my mind 😸 ).

That being said, the above fact was not (and still is not) documented anywhere. I will fix that as part of this issue.

@onobc
Copy link
Contributor Author

onobc commented Oct 18, 2024

  • update docs w/ this limitation and workaround
  • create issue for break dependence on Pulsar auto-configuration

@olegz
Copy link
Contributor

olegz commented Oct 30, 2024

@onobc is there are anything I can do to help to resolve this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants