Scrolling a Column in Board View crashes when fetching further Issues from Server (OD-2078)
empinator opened 1 year ago

Hi Robin,

if I have a board where the amount of issues in a column exceeds the number of directly loaded issues and then try to scroll down it will try to execute a lazy load to fetch further issues. With a certain amount it leads to an Exception being thrown. In my tests this doesn't occur with 80 Issues but it does happen with 150 Issues in one column. See Stacktrace below.

Thanks, e

org.apache.wicket.WicketRuntimeException: Method onRequest of interface org.apache.wicket.behavior.IBehaviorListener targeted at io.onedev.server.web.page.project.issues.boards.CardListPanel$1@256f176 on component [CardListPanel [Component id = body]] threw an exception
	at org.apache.wicket.RequestListenerInterface.internalInvoke(RequestListenerInterface.java:268)
	at org.apache.wicket.RequestListenerInterface.invoke(RequestListenerInterface.java:241)
	at org.apache.wicket.core.request.handler.ListenerInterfaceRequestHandler.invokeListener(ListenerInterfaceRequestHandler.java:248)
	at org.apache.wicket.core.request.handler.ListenerInterfaceRequestHandler.respond(ListenerInterfaceRequestHandler.java:234)
	at org.apache.wicket.request.cycle.RequestCycle$HandlerExecutor.respond(RequestCycle.java:891)
	at org.apache.wicket.request.RequestHandlerStack.execute(RequestHandlerStack.java:64)
	at org.apache.wicket.request.cycle.RequestCycle.execute(RequestCycle.java:260)
	at org.apache.wicket.request.cycle.RequestCycle.processRequest(RequestCycle.java:217)
	at org.apache.wicket.request.cycle.RequestCycle.processRequestAndDetach(RequestCycle.java:288)
	at org.apache.wicket.protocol.ws.AbstractUpgradeFilter.processRequestCycle(AbstractUpgradeFilter.java:70)
	at org.apache.wicket.protocol.http.WicketFilter.processRequest(WicketFilter.java:203)
	at org.apache.wicket.protocol.http.WicketServlet.doPost(WicketServlet.java:159)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
	at io.onedev.server.web.DefaultWicketServlet.lambda$service$0(DefaultWicketServlet.java:45)
	at io.onedev.server.persistence.DefaultSessionManager.lambda$run$0(DefaultSessionManager.java:108)
	at io.onedev.server.persistence.DefaultSessionManager.call(DefaultSessionManager.java:90)
	at io.onedev.server.persistence.DefaultSessionManager.run(DefaultSessionManager.java:107)
	at io.onedev.server.web.DefaultWicketServlet.service(DefaultWicketServlet.java:42)
	at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:799)
	at org.eclipse.jetty.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1656)
	at com.google.inject.servlet.DefaultFilterPipeline.dispatch(DefaultFilterPipeline.java:47)
	at com.google.inject.servlet.GuiceFilter.doFilter(GuiceFilter.java:133)
	at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
	at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1626)
	at io.onedev.server.git.GoGetFilter.doFilter(GoGetFilter.java:87)
	at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
	at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1626)
	at io.onedev.server.git.GitLfsFilter.doFilter(GitLfsFilter.java:454)
	at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
	at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1626)
	at io.onedev.server.git.GitFilter.doFilter(GitFilter.java:363)
	at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
	at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1626)
	at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:61)
	at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108)
	at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137)
	at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:154)
	at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66)
	at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108)
	at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137)
	at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:154)
	at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66)
	at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108)
	at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137)
	at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:154)
	at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66)
	at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:458)
	at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:373)
	at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)
	at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)
	at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:387)
	at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:370)
	at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:154)
	at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
	at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1626)
	at io.onedev.server.security.CorsFilter.doFilter(CorsFilter.java:47)
	at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
	at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1626)
	at io.onedev.server.jetty.DisableTraceFilter.doFilter(DisableTraceFilter.java:28)
	at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
	at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1626)
	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:552)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233)
	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1624)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233)
	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1440)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188)
	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:505)
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1594)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186)
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1355)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
	at org.eclipse.jetty.server.handler.gzip.GzipHandler.handle(GzipHandler.java:772)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
	at org.eclipse.jetty.server.Server.handle(Server.java:516)
	at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:487)
	at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:732)
	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:479)
	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:277)
	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105)
	at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:338)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:315)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:173)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:131)
	at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:409)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:883)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1034)
	at java.base/java.lang.Thread.run(Thread.java:1583)
Caused by: java.lang.reflect.InvocationTargetException
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:118)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at org.apache.wicket.RequestListenerInterface.internalInvoke(RequestListenerInterface.java:258)
	... 90 more
Caused by: java.lang.IllegalArgumentException: A child '' with id '22418' already exists:
[RepeatingView [Component id = cards]]
	at org.apache.wicket.MarkupContainer.add(MarkupContainer.java:237)
	at io.onedev.server.web.page.project.issues.boards.CardListPanel$1.appendMore(CardListPanel.java:72)
	at io.onedev.server.web.behavior.infinitescroll.InfiniteScrollBehavior.respond(InfiniteScrollBehavior.java:56)
	at org.apache.wicket.ajax.AbstractDefaultAjaxBehavior.onRequest(AbstractDefaultAjaxBehavior.java:601)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	... 92 more

  • Robin Shen commented 1 year ago

    Hi @empinator,

    I am unable to reproduce this issue by loading more than 150 issues. Can you please reproduce this with an example database and attach the backup?

  • empinator commented 1 year ago

    I'm still trying to put together a sandbox for you

  • Robin Shen commented 1 year ago

    Thanks!

  • empinator commented 1 year ago

    I'm still having issues creating a sandbox without sensitive data, sorry!

    however, I did a little debugging myself and found out that indeed the sql query is returning certain issues again on the next offset

    select
        issue0_.o_id as o_id1_28_,
        issue0_.o_number as o_numbe10_28_,
        issue0_.o_title as o_title18_28_,
        issue0_.o_boardPosition as o_boardp2_28_,
        issue0_.o_commentCount as o_commen3_28_,
        issue0_.o_confidential as o_confid4_28_,
        issue0_.o_description as o_descri5_28_,
        issue0_.o_LAST_ACTIVITY_DATE as o_last_a6_28_,
        issue0_.o_LAST_ACTIVITY_DESCRIPTION as o_last_a7_28_,
        issue0_.o_LAST_ACTIVITY_USER as o_last_23_28_,
        issue0_.o_messageId as o_messag8_28_,
        issue0_.o_noSpaceTitle as o_nospac9_28_,
        issue0_.o_numberScope_id as o_numbe24_28_,
        issue0_.o_ownEstimatedTime as o_ownes11_28_,
        issue0_.o_ownSpentTime as o_ownsp12_28_,
        issue0_.o_pinDate as o_pinda13_28_,
        issue0_.o_progress as o_progr14_28_,
        issue0_.o_project_id as o_proje25_28_,
        issue0_.o_state as o_state15_28_,
        issue0_.o_stateOrdinal as o_state16_28_,
        issue0_.o_submitDate as o_submi17_28_,
        issue0_.o_submitter_id as o_submi26_28_,
        issue0_.o_totalEstimatedTime as o_total19_28_,
        issue0_.o_totalSpentTime as o_total20_28_,
        issue0_.o_uuid as o_uuid21_28_,
        issue0_.o_voteCount as o_votec22_28_
    from
        o_Issue issue0_
    where
        (
            issue0_.o_project_id in (
                18
                )
                or (
                       issue0_.o_project_id in (
                           18
                           )
                       )
                and (
                       exists (
                           select
                               issueautho1_.o_id
                           from
                               o_IssueAuthorization issueautho1_
                           where
                               issueautho1_.o_issue_id=issue0_.o_id
                             and issueautho1_.o_user_id=1
                       )
                       )
            )
      and (
        exists (
            select
                issuesched2_.o_id
            from
                o_IssueSchedule issuesched2_
                    inner join
                o_Iteration iteration3_
                on issuesched2_.o_iteration_id=iteration3_.o_id
            where
                issuesched2_.o_issue_id=issue0_.o_id
              and (
                lower(iteration3_.o_name) like '4.13.0'
                )
        )
        )
      and issue0_.o_state='Closed'
    order by
        issue0_.o_boardPosition asc limit 25 OFFSET :offset;
    

    offset 0 returns the same Issue at the last position as offset = 25 on the first position

    It seems like the reason is that ordering by boardPosition alone is not deterministic and it requires another "order by" field to make them unique within the same board position

    adding a sort by issueId fixed the query

    ...
        )
      and issue0_.o_state='Closed'
    order by
        issue0_.o_boardPosition asc, issue0_.o_id asc limit 25 OFFSET 25;
    ...
    

    I think the according code positions would be

    IssueBoardsPage.java

    to be exended with

    ...
    		sort.setDirection(EntitySort.Direction.ASCENDING);
    		sort.setField(NAME_BOARD_POSITION);
    		query.getSorts().add(sort);
    		EntitySort sort2 = new EntitySort();
    		// Sorting by ID to make result deterministic
    		sort2.setDirection(EntitySort.Direction.ASCENDING);
    		sort2.setField(NAME_ID);
    		query.getSorts().add(sort2);
    ...
    

    Do you think that's sufficient to resolve the issue?

  • Robin Shen commented 1 year ago

    Thanks for your investigation. Will get this fixed in next patch release.

  • OneDev changed state to 'Closed' 1 year ago
    Previous Value Current Value
    Open
    Closed
  • OneDev commented 1 year ago

    State changed as code fixing the issue is committed (9ec7fc7d)

  • OneDev changed state to 'Released' 1 year ago
    Previous Value Current Value
    Closed
    Released
  • OneDev commented 1 year ago

    State changed as build OD-5529 is successful

issue 1/1
Type
Bug
Priority
Normal
Assignee
Affected Versions
11.0.8
Labels
No labels
Issue Votes (0)
Watchers (2)
Reference
OD-2078
Please wait...
Connection lost or session expired, reload to recover
Page is in error, reload to recover