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

StackOverflowError when one service implements another service #52

Open
randers-bit opened this issue Sep 13, 2021 · 4 comments
Open

StackOverflowError when one service implements another service #52

randers-bit opened this issue Sep 13, 2021 · 4 comments

Comments

@randers-bit
Copy link

randers-bit commented Sep 13, 2021

This occurs in Scala
Lagom: 1.6.5
Java: Adopt JDK 11
SBT: 1.5.2

Hello,
i tried to use this library with my lagom project and i found that after starting software throws StackOverflowError.
After i saw this i wanted to check if this is because of my code or something else so i forked example repository.
I changed scala project to be similar what i use in my project.
First i changed api and impl to pets-api and pets-impl. Next i changed sbt to 1.5.2. I did changes in build.sbt ( in is replaced by / )
Next i created (copy+paste of pets api/impl) vets-api and vets-impl (i removed all endpoints but: find).
I copied all annotations and changed some descriptions (like description pets->vets), and removed servers entries(because i don't use one ).
Next i added that vets-impl depends on pets-api

lazy val `vets-impl` = ( project in file( "vets-impl" ) )
    [...]
    .dependsOn( `pets-api`, `vets-api` )

and in lagom loader i created PetsService implementation.

    lazy val petsService: PetsService = serviceClient.implement[ PetsService ]

    // Bind the service that this server provides
    override lazy val lagomServer = {
        val service = wire[ VetsServiceImpl ]
        serverFor[ VetsService ]( service )
            .additionalRouter( wire[ OpenAPIRouter ].router( service ) )
    }

Then i added petsService to vets-impl in constructor

class VetsServiceImpl( petsService: PetsService ) extends VetsService {

After this changes, when i do runAll vets-impl throws StackOverflowError.

17:56:44.861 [info] akka.event.slf4j.Slf4jLogger [] - Slf4jLogger started
17:56:44.939 [info] akka.event.slf4j.Slf4jLogger [] - Slf4jLogger started
17:56:45.684 [info] play.core.server.AkkaHttpServer [] - Listening for HTTP on /127.0.0.1:9000
17:56:45.747 [info] play.core.server.AkkaHttpServer [] - Listening for HTTP on /127.0.0.1:9001
17:56:50.054 [info] akka.event.slf4j.Slf4jLogger [] - Slf4jLogger started
17:56:50.950 [info] play.api.Play [] - Application started (Dev) (no global state)
17:56:54.498 [info] akka.event.slf4j.Slf4jLogger [] - Slf4jLogger started
[error] stack trace is suppressed; run 'last vets-impl / lagomRun' for the full output
[error] (vets-impl / lagomRun) java.lang.StackOverflowError
[error] Total time: 14 s, completed 13 wrz 2021, 17:56:54
[IJ]18:06:19.707 [info] play.core.server.AkkaHttpServer [] - Stopping Akka HTTP server...
18:06:19.707 [info] play.core.server.AkkaHttpServer [] - Stopping Akka HTTP server...
18:06:19.711 [info] play.core.server.AkkaHttpServer [] - Terminating server binding for /127.0.0.1:9000
18:06:19.711 [info] play.core.server.AkkaHttpServer [] - Terminating server binding for /127.0.0.1:9001
18:06:19.742 [info] play.core.server.AkkaHttpServer [] - Running provided shutdown stop hooks

My fork is here

@randers-bit
Copy link
Author

randers-bit commented Sep 13, 2021

On another machine i confirmed that on Adopt JDK 11 code throws same overflow exception.

@liannelee
Copy link

Hello, I'm getting the same stackoverflow error when adding the additional router to the service loader as my service also implements another service.

Lagom: 1.6.5
Java: JDK 11
SBT: 1.2.8 (also tried with 1.3.2 as suggested in example)

Any advice on this?

@GMShuhr
Copy link

GMShuhr commented Oct 14, 2021

Hello, I have the same problem. The cause seems to be that the line
val service = wire[VetsServiceImpl] causes the right hand side of this assignment to be created instantly (when lagomServer is accessed and the lazy right hand side of the declaration of lagomServer gets executed). Before that, the expression wire[VetsServiceImpl] was only put as a parameter into the method serverFor which in turn evaluates the parameter lazily.

@randers-bit
Copy link
Author

@GMShuhr nice catch. I didn't think this could be a cause for this.
I did small experiments in my fork and changed service to be lazy, or got it outside of lagomServer function scope for example like this

   lazy val petsService: PetsService = serviceClient.implement[ PetsService ]

    //This got outside of lagomServer{} scope and is declared directly in loader
    lazy val service: VetsServiceImpl = wire[ VetsServiceImpl ]

    // Bind the service that this server provides
    override lazy val lagomServer = serverFor[ VetsService ]( service ).additionalRouter( wire[ OpenAPIRouter ].router( service ) )

But still same overflow exception exists (like i thought so). When i removed dependency to PetsService in VetsServiceImpl lagom server started normally.

When testing i found something which maybe can be helpfull. When i declared service outside of scope i found one thing: service variable needs to have type declared. When this is not done like here:

lazy val service = wire[ VetsServiceImpl ]
    
// Bind the service that this server provides
override lazy val lagomServer = serverFor[ VetsService ]( service ).additionalRouter( wire[ OpenAPIRouter ].router( service ) )

lagom throws this exception:

[...]/impl/VetsLoader.scala:34:35: recursive lazy value service needs type

Especially i think word recursive in this meaning has a great value. If something loops with this recursion it could cause overflow exception. Maybe im wrong, i don't know lagom that much in service implementation.

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

3 participants