Uploaded image for project: 'Kuali Rice Development'
  1. Kuali Rice Development
  2. KULRICE-10549

Thread pool configuration and queueing algorithm

    Details

    • Type: Improvement
    • Status: Closed
    • Priority: Major
    • Resolution: Complete
    • Affects Version/s: None
    • Fix Version/s: 2.4
    • Security Level: Public (Public: Anyone can view)
    • Labels:
      None
    • Epic Link:
    • Rice Module:
      KRAD
    • Sprint:
      2.4.0-m2 KRAD Sprint 3, 2.4.0-m2 KRAD Sprint 4, 2.4.0-m3 KRAD Sprint 1
    • KAI Review Status:
      Not Required
    • KTI Review Status:
      Not Required
    • Code Review Status:
      Not Required
    • Include in Release Notes?:
      Yes

      Description

      Thread pool configuration and queueing algorithm:
      Assemble processing tasks into a concurrent execution queue and establish a thread pool and mechanism to manage submission and notification.

        Attachments

          Issue Links

            Activity

            Hide
            mwfyffe Mark Fyffe (Inactive) added a comment -

            Continuing work started on KULRICE-10547 to refactor view/component lifecycle into discrete processing tasks.

            Moved viewStatus property from View to ComponentBase, and added to Component interface.

            The initialize phase, and all related helper methods has moved from ViewLifecycle to InitializeComponentPhase. The initialized phase is now tail recursive, and is ready for multi-threaded queueing.

            Now working to refactor apply model and finalize phases.

            Show
            mwfyffe Mark Fyffe (Inactive) added a comment - Continuing work started on KULRICE-10547 to refactor view/component lifecycle into discrete processing tasks. Moved viewStatus property from View to ComponentBase, and added to Component interface. The initialize phase, and all related helper methods has moved from ViewLifecycle to InitializeComponentPhase. The initialized phase is now tail recursive, and is ready for multi-threaded queueing. Now working to refactor apply model and finalize phases.
            Hide
            mwfyffe Mark Fyffe (Inactive) added a comment -

            Completed lifecycle phase refactoring and queueing algorithm.

            1. Moved buildView() from ViewService to ViewLifecycle.
            2. Added isInitialized(), isModelApplied(), isFinal(), and isRendered() methods to Component.
            3. Moved performComponentApplyModel() and all related methods from ViewLifecycle to discrete lifecycle phase processing task ApplyModelComponentPhase.
            4. Moved performComponentFinalize() and all related methods from ViewLifecycle to discrete lifecycle phase processing task FinalizeComponentPhase.
            5. Changed spawnSubLifecycle to queue sub-lifecycle phases after applying component IDs, rather than process inline.
            6. Modified inline references to performComponentInitialize to call spawnSubLifecycle instead.

            Cleanup following implementation of the queueing algorithm took a little longer than expected. I had initially set IAE to be thrown when attempting to queue a lifecycle phase for a component that already has the targeted view status, and for ISE to be thrown when attempting to process a component without the required view status. This helped uncover some lifecycle processing issues, but prior to commit I downgraded these to warning conditions for further review without impacting stability. Cleanup uncovered by these conditions:

            1. Duplicate entry of breadcrumb items in View.getComponentsForLifecycle()
            2. Inclusion of fieldLabel as nested under FieldBase when isLabelRendered() is true. In this case, the label becomes a child of the owning group when LabelSeparateModifier runs.
            3. Several areas where performApplyModel was called twice: once from spawnSubLifecycle, then again as a nested component.

            The only page I found where invalid status warnings still appear is Kitchen Sink "Other Examples". Remaining KRAD pages in sampleapp and krad-sampleapp appear to work well without lifecycle phase violations in single-threaded mode.

            Will configure a thread pool and convert queueing to multi-threaded operation once KULRICE-10548 is complete.

            Show
            mwfyffe Mark Fyffe (Inactive) added a comment - Completed lifecycle phase refactoring and queueing algorithm. Moved buildView() from ViewService to ViewLifecycle. Added isInitialized(), isModelApplied(), isFinal(), and isRendered() methods to Component. Moved performComponentApplyModel() and all related methods from ViewLifecycle to discrete lifecycle phase processing task ApplyModelComponentPhase. Moved performComponentFinalize() and all related methods from ViewLifecycle to discrete lifecycle phase processing task FinalizeComponentPhase. Changed spawnSubLifecycle to queue sub-lifecycle phases after applying component IDs, rather than process inline. Modified inline references to performComponentInitialize to call spawnSubLifecycle instead. Cleanup following implementation of the queueing algorithm took a little longer than expected. I had initially set IAE to be thrown when attempting to queue a lifecycle phase for a component that already has the targeted view status, and for ISE to be thrown when attempting to process a component without the required view status. This helped uncover some lifecycle processing issues, but prior to commit I downgraded these to warning conditions for further review without impacting stability. Cleanup uncovered by these conditions: Duplicate entry of breadcrumb items in View.getComponentsForLifecycle() Inclusion of fieldLabel as nested under FieldBase when isLabelRendered() is true. In this case, the label becomes a child of the owning group when LabelSeparateModifier runs. Several areas where performApplyModel was called twice: once from spawnSubLifecycle, then again as a nested component. The only page I found where invalid status warnings still appear is Kitchen Sink "Other Examples". Remaining KRAD pages in sampleapp and krad-sampleapp appear to work well without lifecycle phase violations in single-threaded mode. Will configure a thread pool and convert queueing to multi-threaded operation once KULRICE-10548 is complete.
            Hide
            mwfyffe Mark Fyffe (Inactive) added a comment -

            Completed thread pool configuration and phase queueing algorithm. Several clean-up items following recent refactoring accompany this update.

            View lifecycle is now controlled by the following configuration parameters:

            • rice.krad.lifecycle.trace - enables the logging of processing data related to lifecycle phase processing. This property is particularly useful for troubleshooting asynchronous operation. Default is false.
            • rice.krad.lifecycle.asynchronous - enables asynchronous phase processing. When set to true, lifecycle phases will be performed using pooled worker threads. When false, the original single-threaded lifecycle process is used. Default is false.
            • rice.krad.lifecycle.asynchronous.minThreads - defines the minimum number of worker threads to maintain when asynchronous processing is enabled. This setting has no effect on single-threaded lifecycle processing. The default setting is 4.
            • rice.krad.lifecycle.asynchronous.minThreads - defines the maximum number of worker threads to allow in the pool when asynchronous processing is enabled. This setting has no effect on single-threaded lifecycle processing. The default setting is 48.
            • rice.krad.lifecycle.asynchronous.timeout - defines the time, in milliseconds, to wait for asynchronous lifecycle processing to complete before giving up. One the timeout has reached, any pending phases will be canceled.

            Changes related to this feature are:

            • Converted all MessageMap lists to be synchronized. In single-threaded mode, these lists should be effectively thread-local but in multi-threaded mode (including multiple requests), they are important to synchronize as recommended in the API documentation for AutoPopulatingList.
            • Moved importTemplate() calls from the finalize phase to the render phase, since rendering may take place in a different thread, which may have a different rendering context.
            • Restructured prepare() and LifecyclePhaseFactory() methods
            • Split processing details out from ViewLifecycle into the new ViewLifecycleProcessor interface.
              • The original single-threaded behavior is supported by SynchronousViewLifecycleProcessor.
              • The multi-threaded behavior is supported by AsynchronousViewLifecycleProcessor.
            • Converted lifecycle phase tree for bottom-up traversal only.
              • Child and sibling references have been removed in favor of pending counts. This consideration eliminates the need to synchronize on lists during phase complete notification.
              • Phases now have only a single predecessor, rather than a list of mulitple predecssors. Precessor phases are assigned dynamically.
            • Pushed rendering phase creation down to initializeSuccessors().
            • Decoupled rendering phase from finalize phase, converted references to normal successor/predecessor relationships.
            • Converted RecycleUtils to use a concurrent queue instead of maintaining separate queues per thread.
            • Refactored LifecyclePhaseFactory and LifecycleTaskFactory to use RecycleUtils instead of internal recycling mechanisms.
            Show
            mwfyffe Mark Fyffe (Inactive) added a comment - Completed thread pool configuration and phase queueing algorithm. Several clean-up items following recent refactoring accompany this update. View lifecycle is now controlled by the following configuration parameters: rice.krad.lifecycle.trace - enables the logging of processing data related to lifecycle phase processing. This property is particularly useful for troubleshooting asynchronous operation. Default is false. rice.krad.lifecycle.asynchronous - enables asynchronous phase processing. When set to true, lifecycle phases will be performed using pooled worker threads. When false, the original single-threaded lifecycle process is used. Default is false. rice.krad.lifecycle.asynchronous.minThreads - defines the minimum number of worker threads to maintain when asynchronous processing is enabled. This setting has no effect on single-threaded lifecycle processing. The default setting is 4. rice.krad.lifecycle.asynchronous.minThreads - defines the maximum number of worker threads to allow in the pool when asynchronous processing is enabled. This setting has no effect on single-threaded lifecycle processing. The default setting is 48. rice.krad.lifecycle.asynchronous.timeout - defines the time, in milliseconds, to wait for asynchronous lifecycle processing to complete before giving up. One the timeout has reached, any pending phases will be canceled. Changes related to this feature are: Converted all MessageMap lists to be synchronized. In single-threaded mode, these lists should be effectively thread-local but in multi-threaded mode (including multiple requests), they are important to synchronize as recommended in the API documentation for AutoPopulatingList. Moved importTemplate() calls from the finalize phase to the render phase, since rendering may take place in a different thread, which may have a different rendering context. Restructured prepare() and LifecyclePhaseFactory() methods Split processing details out from ViewLifecycle into the new ViewLifecycleProcessor interface. The original single-threaded behavior is supported by SynchronousViewLifecycleProcessor. The multi-threaded behavior is supported by AsynchronousViewLifecycleProcessor. Converted lifecycle phase tree for bottom-up traversal only. Child and sibling references have been removed in favor of pending counts. This consideration eliminates the need to synchronize on lists during phase complete notification. Phases now have only a single predecessor, rather than a list of mulitple predecssors. Precessor phases are assigned dynamically. Pushed rendering phase creation down to initializeSuccessors(). Decoupled rendering phase from finalize phase, converted references to normal successor/predecessor relationships. Converted RecycleUtils to use a concurrent queue instead of maintaining separate queues per thread. Refactored LifecyclePhaseFactory and LifecycleTaskFactory to use RecycleUtils instead of internal recycling mechanisms.

              People

              • Assignee:
                mwfyffe Mark Fyffe (Inactive)
                Reporter:
                jkneal Jerry Neal (Inactive)
              • Votes:
                0 Vote for this issue
                Watchers:
                2 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved:

                  Time Tracking

                  Estimated:
                  Original Estimate - 6 hours Original Estimate - 6 hours
                  6h
                  Remaining:
                  Remaining Estimate - 0 minutes
                  0m
                  Logged:
                  Time Spent - 1 day, 2 hours
                  1d 2h