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

Services exceptions in Init got swallowed #381

Open
DraTeots opened this issue Nov 13, 2024 · 4 comments
Open

Services exceptions in Init got swallowed #381

DraTeots opened this issue Nov 13, 2024 · 4 comments

Comments

@DraTeots
Copy link
Collaborator

DraTeots commented Nov 13, 2024

I am using a new component methods of Services:

    class MyService : public JService
    {
    public:
        explicit MyService () : JService() {}
        ~MyService () override = default;

        void Init() override {
            throw std::runtime_error("will not be shown");

            // This code will never be called and noone will know about it
            int x = 5; 
       }
};

Then I am using it via Serivce component class

struct ReconstructFactory : public JOmniFactory<ReconstructFactory> {
   Service<MyService> m_service{this};
   // ... 

MyService ::Init() is called during app->Initialize(), but nothing is reporting that there was an exception and the service is basically is not initialized. As usually happens in such cases, the app fails later with obscure null pointer segfault and it is difficult to debug as the indicating exception is silently swallowed and everything just continues to run after a major resource load failure.

I would propose a hard fail instead.

@nathanwbrei
Copy link
Collaborator

nathanwbrei commented Nov 17, 2024

Hey Dmitry! I can't reproduce the problem I think you are describing. I added a test case verifying that Init() does NOT swallow exceptions here:

TEST_CASE("JServiceTests_ExceptionInInit") {
JApplication app;
app.ProvideService(std::make_shared<DummyService>());
try {
app.Initialize();
REQUIRE(1 == 0); // Shouldn't be reachable
auto sut = app.GetService<DummyService>();
REQUIRE(1 == 0); // Definitely shouldn't be reachable
}
catch (JException& e) {
REQUIRE(e.GetMessage() == "Something goes wrong");
REQUIRE(e.type_name == "jana::jservicetests::DummyService");
REQUIRE(e.function_name == "JService::Init");
}
}

Can you provide more info about the problem you are having?

In the process I noticed several other problems with JService which I've quickly fixed:

  • JService::Init() is supposed to always be called within JApplication::Initialize(), in order to collect all JParameters. However, it was only being called lazily, so if you provided a JService using JApplication::ProvideService() but never fetched it using JApplication::GetService() or JOmniFactory::Service, JService::Init() wouldn't be called.
  • JService has a GetTypeName() now, which wasn't being set. Among other things, this makes the JException less informative.

@DraTeots
Copy link
Collaborator Author

I will try to provide a clean reproducer. I do JApplication::ProvideService and then Service in... another service believe. And raised exceptions got silently swallowed - no output at all. May it be that services initialization goes before log initialization and such? Because if I print something from service init, it apears above all other usual jana output.

@nathanwbrei
Copy link
Collaborator

nathanwbrei commented Nov 17, 2024

Service initialization can happen very early, if you call JApplication::GetService() before JApplication::Initialize(). This is a helpful clue.

A lot of internal JANA machinery is represented by JServices as well, which isn't working out as well as I'd hoped, and most of those get Init()ed during JApplication::Initialize(). This can cause weird scenarios to arise, particularly if a user-provided JService is initialized too early and fetches a JANA-internal service, which will force the initialization of the JANA-internal service potentially too early. I wish I could enforce that Services can only be retrieved from inside component callbacks, but if I recall correctly, that broke too many things.

@nathanwbrei
Copy link
Collaborator

One annoying little detail that may assist in your debugging: JComponentManager creates a "dummy" JFactorySet simply for the purpose of calling JFactory::Init() and collecting JParameters. Exceptions for the dummy JFactorySet do indeed get swallowed. The JFactorySets that actually get used during JApplication::Run() are created much later, by JEventPool, and they will be initialized with no exception swallowing. This has caused Raiqa a lot of trouble because it shows up in the debugger when the problem is elsewhere. Maybe it's causing you trouble too?

At any rate, the dummy factoryset problem will hopefully go away once I add support for event pool scaling, hopefully to be included in the enormous PR that's in the works.

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

No branches or pull requests

2 participants