isopropylcyanide / Jwt-Spring-Security-JPA

Backend MVP showcasing JWT (Json Web Token) authentication with multiple login, timeout / refresh / logout (with in memory invalidation) using Spring Security & MySQL JPA.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

javax.persistence.NonUniqueResultException: query did not return a unique result: 2 (this error happens only through Heroku server-free option)

WoodySide opened this issue · comments

When I send put request Log in locally and then test it via Postman it works perfectly fine, but when I do through Heroku server sometimes unexpectedly it adds 2 device info on the same user into DB, which leads to ambiguous situation in DB, my problem is I am not sure where exactly the problem, whether it's with the project code, or with Heroku server, because if you're using the free Heroku option it falls asleep in a while, so maybe that's the key, and that's why I have this error.

There are all logs from Heroku server down below:

DEBUG SQL select userdevice0_.user_device_id as user_dev1_8_, userdevice0_.created_at as created_2_8_, userdevice0_.updated_at as updated_3_8_, userdevice0_.device_id as device_i4_8_, userdevice0_.device_type as device_t5_8_, userdevice0_.is_refresh_active as is_refre6_8_, userdevice0_.notification_token as notifica7_8_, userdevice0_.user_id as user_id8_8_ from user_device userdevice0_ left outer join users user1_ on userdevice0_.user_id=user1_.user_id where user1_.user_id=? 2021-12-09T18:39:52.900225+00:00 app[web.1]: Hibernate: select userdevice0_.user_device_id as user_dev1_8_, userdevice0_.created_at as created_2_8_, userdevice0_.updated_at as updated_3_8_, userdevice0_.device_id as device_i4_8_, userdevice0_.device_type as device_t5_8_, userdevice0_.is_refresh_active as is_refre6_8_, userdevice0_.notification_token as notifica7_8_, userdevice0_.user_id as user_id8_8_ from user_device userdevice0_ left outer join users user1_ on userdevice0_.user_id=user1_.user_id where user1_.user_id=? 2021-12-09T18:39:52.903103+00:00 app[web.1]: 21-12-09 Thu 18:39:52.902 DEBUG SQL select refreshtok0_.token_id as token_id1_4_1_, refreshtok0_.created_at as created_2_4_1_, refreshtok0_.updated_at as updated_3_4_1_, refreshtok0_.expiry_dt as expiry_d4_4_1_, refreshtok0_.refresh_count as refresh_5_4_1_, refreshtok0_.token as token6_4_1_, refreshtok0_.user_device_id as user_dev7_4_1_, userdevice1_.user_device_id as user_dev1_8_0_, userdevice1_.created_at as created_2_8_0_, userdevice1_.updated_at as updated_3_8_0_, userdevice1_.device_id as device_i4_8_0_, userdevice1_.device_type as device_t5_8_0_, userdevice1_.is_refresh_active as is_refre6_8_0_, userdevice1_.notification_token as notifica7_8_0_, userdevice1_.user_id as user_id8_8_0_ from refresh_token refreshtok0_ inner join user_device userdevice1_ on refreshtok0_.user_device_id=userdevice1_.user_device_id where refreshtok0_.user_device_id=? 2021-12-09T18:39:52.903170+00:00 app[web.1]: Hibernate: select refreshtok0_.token_id as token_id1_4_1_, refreshtok0_.created_at as created_2_4_1_, refreshtok0_.updated_at as updated_3_4_1_, refreshtok0_.expiry_dt as expiry_d4_4_1_, refreshtok0_.refresh_count as refresh_5_4_1_, refreshtok0_.token as token6_4_1_, refreshtok0_.user_device_id as user_dev7_4_1_, userdevice1_.user_device_id as user_dev1_8_0_, userdevice1_.created_at as created_2_8_0_, userdevice1_.updated_at as updated_3_8_0_, userdevice1_.device_id as device_i4_8_0_, userdevice1_.device_type as device_t5_8_0_, userdevice1_.is_refresh_active as is_refre6_8_0_, userdevice1_.notification_token as notifica7_8_0_, userdevice1_.user_id as user_id8_8_0_ from refresh_token refreshtok0_ inner join user_device userdevice1_ on refreshtok0_.user_device_id=userdevice1_.user_device_id where refreshtok0_.user_device_id=? 2021-12-09T18:39:52.905905+00:00 app[web.1]: 21-12-09 Thu 18:39:52.905 DEBUG SQL select refreshtok0_.token_id as token_id1_4_1_, refreshtok0_.created_at as created_2_4_1_, refreshtok0_.updated_at as updated_3_4_1_, refreshtok0_.expiry_dt as expiry_d4_4_1_, refreshtok0_.refresh_count as refresh_5_4_1_, refreshtok0_.token as token6_4_1_, refreshtok0_.user_device_id as user_dev7_4_1_, userdevice1_.user_device_id as user_dev1_8_0_, userdevice1_.created_at as created_2_8_0_, userdevice1_.updated_at as updated_3_8_0_, userdevice1_.device_id as device_i4_8_0_, userdevice1_.device_type as device_t5_8_0_, userdevice1_.is_refresh_active as is_refre6_8_0_, userdevice1_.notification_token as notifica7_8_0_, userdevice1_.user_id as user_id8_8_0_ from refresh_token refreshtok0_ inner join user_device userdevice1_ on refreshtok0_.user_device_id=userdevice1_.user_device_id where refreshtok0_.user_device_id=? 2021-12-09T18:39:52.905963+00:00 app[web.1]: Hibernate: select refreshtok0_.token_id as token_id1_4_1_, refreshtok0_.created_at as created_2_4_1_, refreshtok0_.updated_at as updated_3_4_1_, refreshtok0_.expiry_dt as expiry_d4_4_1_, refreshtok0_.refresh_count as refresh_5_4_1_, refreshtok0_.token as token6_4_1_, refreshtok0_.user_device_id as user_dev7_4_1_, userdevice1_.user_device_id as user_dev1_8_0_, userdevice1_.created_at as created_2_8_0_, userdevice1_.updated_at as updated_3_8_0_, userdevice1_.device_id as device_i4_8_0_, userdevice1_.device_type as device_t5_8_0_, userdevice1_.is_refresh_active as is_refre6_8_0_, userdevice1_.notification_token as notifica7_8_0_, userdevice1_.user_id as user_id8_8_0_ from refresh_token refreshtok0_ inner join user_device userdevice1_ on refreshtok0_.user_device_id=userdevice1_.user_device_id where refreshtok0_.user_device_id=? 2021-12-09T18:39:52.909292+00:00 app[web.1]: 21-12-09 Thu 18:39:52.908 ERROR ServiceAspect Exception in com.webApp.service.UserDeviceService.findByUserId() with cause = {} 2021-12-09T18:39:52.909294+00:00 app[web.1]: javax.persistence.NonUniqueResultException: query did not return a unique result: 2

And in the Heroku DB, when this happens, there just two parts fully identical data with the same user_id, which is wrong, and that's why -> error, so again it's not all the time, it's time to time, but It can crash all the project, if you have any ideas why this might have happened, please share it with me.

Thanks in advance.

Hey there, following up on your separate email, this again doesn't capture a clear steps for me to reproduce. I'm not quite sure why two devices are getting registered for the user. These may be two separate calls in quick succession.

I) A unique constraint might be all that you need. For the purposes of demo, I've not quite added all the unique indices applicable for the entities. It's really trivial to add a unique index on userID, deviceID. This way, the 2nd call during device login would fail as expected.

II) To answer your question over email on why exactly there is Device in the project, the device context is passed in through login information so that you have the ability to login/logout from multiple devices and logging out from a particular device doesn't log you out from all.

Feel free to fork this repo and drop the DeviceContext models altogether. The login API would work without a device context and the logout API's would change accordingly as well

Not sure if the Heroku server is doing anything funny. Essentially, it should just do what you program it to do.

You should be able to break down the flow API by API and need to come up with a minimum reproducible scenario. Otherwise, my hands are tied as I'm not sure what sequence of actions is being performed.

The code should be straight forward and easy to understand. You should be able to step through the breakpoints and debug the flow locally. I don't have an in-depth knowledge of Heroku. Perhaps try running heroku local or heroku run -a and try to reproduce it locally.

heroku logs should then pinpoint the source of APIs that led to the error.

If you login from two separate device, both should pass a unique identifier. In this case, there will be two user_devices actively linked against the user. There's no overwrite (unless both pass the same identifier)

So current problem is every time I log in with different Device data(as if from different devices) it overwrites device data on DB, not creating a new Device info linked to the same user, down below there are some evidences of it, Postman + what's going on DB after Log in request, I might be doing something wrong, so any help would be appreciated, thanks a lot
Снимок экрана 2021-12-17 в 19 14 20
Снимок экрана 2021-12-17 в 19 15 12
Снимок экрана 2021-12-17 в 19 15 26
Снимок экрана 2021-12-17 в 19 15 48
in advance!

Hey @WoodySide thanks for sharing the steps. I can confirm that this is a bug. I'll work towards fixing this promptly.

@WoodySide I've landed #60. Can you give it a go and confirm if the fix works for you?

@WoodySide I've landed #60. Can you give it a go and confirm if the fix works for you?

It is working perfectly fine now, thanks a lot!)