{"id":13698934,"url":"https://github.com/victorizbitskiy/zconcurrency_api","last_synced_at":"2025-10-24T05:30:21.262Z","repository":{"id":41201718,"uuid":"328233016","full_name":"victorizbitskiy/zconcurrency_api","owner":"victorizbitskiy","description":"ABAP Сoncurrency API ","archived":false,"fork":false,"pushed_at":"2024-08-04T09:01:47.000Z","size":1244,"stargazers_count":43,"open_issues_count":1,"forks_count":12,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-30T22:51:34.047Z","etag":null,"topics":["abap","abap-concurrency-api","parallel-processing-in-abap"],"latest_commit_sha":null,"homepage":"","language":"ABAP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/victorizbitskiy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-01-09T19:42:50.000Z","updated_at":"2025-01-14T06:20:49.000Z","dependencies_parsed_at":"2024-09-21T20:02:12.443Z","dependency_job_id":"9648f2a9-7ee9-4774-9e1b-e23c9ace0e39","html_url":"https://github.com/victorizbitskiy/zconcurrency_api","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/victorizbitskiy%2Fzconcurrency_api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/victorizbitskiy%2Fzconcurrency_api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/victorizbitskiy%2Fzconcurrency_api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/victorizbitskiy%2Fzconcurrency_api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/victorizbitskiy","download_url":"https://codeload.github.com/victorizbitskiy/zconcurrency_api/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":237915423,"owners_count":19386724,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["abap","abap-concurrency-api","parallel-processing-in-abap"],"created_at":"2024-08-02T19:00:54.908Z","updated_at":"2025-10-24T05:30:15.939Z","avatar_url":"https://github.com/victorizbitskiy.png","language":"ABAP","funding_links":[],"categories":["Categories"],"sub_categories":["🛤️ Threading"],"readme":"\u003cimg src=\"https://github.com/victorizbitskiy/zconcurrency_api/blob/main/logo/octo.svg\" height=\"100px\"/\u003e\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/victorizbitskiy/zconcurrency_api/blob/main/LICENSE)\n![ABAP 7.00+](https://img.shields.io/badge/ABAP-7.00%2B-brightgreen)\n[![Code Statistics](https://img.shields.io/badge/CodeStatistics-abaplint-blue)](https://abaplint.app/stats/victorizbitskiy/zconcurrency_api)\n\nTranslations:\n- [:ru: На русском языке](https://github.com/victorizbitskiy/zconcurrency_api/tree/main/translations/ru) \n\n## `ABAP Concurrency API`\n\nAPI for parallel processing based on the SPTA Framework.  \n\n`Note`:  The initial idea was to make this API similar to the [Java Concurrency API](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/concurrent/package-summary.html). \nTherefore, the name `ABAP Concurrency API` was chosen. However, in our case, calculations are performed not `concurrently` but `in parallel`.  \nFor more details please see [this](https://wiki.haskell.org/Parallelism_vs._Concurrency) explanation.\n\n---\n\n\u003cp align=\"center\"\u003eDon't forget to click ⭐ if you like the project!\u003cp\u003e\n\n---\n\n# Table of contents\n1. [What it is?](#what-it-is)\n2. [What is this for?](#what-is-this-for)\n3. [Installation](#installation)\n4. [Usage](#usage)\n5. [Usage. HCM module](#using-in-the-HCM-module)\n6. [Diagrams](#diagrams)\n7. [Dependencies](#dependencies)\n8. [Limitations](#limitations)\n9. [How to contribute](#how-to-contribute)\n10. [Got questions](#Got-questions)\n11. [Logo](#logo)\n\n## What it is?\n\nUtility classes useful in parallel programming.\n\n## What is this for?\n\nImplementing parallel computing in ABAP typically involves the following steps:\n\n1. Creating an RFC function module\n2. **Implementation of business logic** inside it\n3. Asynchronous calling RFC function module in a loop\n4. Waiting for execution and **getting results of work**\n\nIf you look at the resulting list, you will notice that, by and large, we are only interested in steps **`2`** and **`4`**.\nEverything else is routine work that takes time every time and, potentially, can be a source of errors.\n\nTo avoid generating an RFC function module every time you need to do parallel processing, you can use the SPTA Framework provided by the vendor.   \n\nThe SPTA Framework is a good tool, but its interface leaves a lot to be desired. Because of this, the developer has to make a lot of effort to implement the parallelization process itself.\n\nIn addition, writing clean code using the SPTA Framework directly is also not the easiest task. You need to be a real ninja to avoid using global variables. After all, the code can be confusing and difficult to maintain.\n\nThe `ABAP Concurrency API` avoids these problems. With it, you can allow yourself to think more abstractly.\nYou don't need to focus on parallelization. Instead, you can spend more time on the business logic of your application.\n\n## Installation\n\nInstallation is done with [abapGit](http://www.abapgit.org).\n\n## Usage\n\nLet's consider a simple task:  \n\n*You need to find the squares of numbers from **`1`** to **`10`***.\n\nThe square of each of the numbers will be found in a separate task/process.  \nThe example is detached from the real world, but it is enough to understand how to work with the API.\n\nFirst, let's create the 3 local classes: *Context*, *Task* and *Result*. \nYou can choose which classes to create (local or global).  \n\n1. **lcl_contex**, an object of this class encapsulates the task parameters.\n   The use of this class is optional. You can do without it by passing the task parameters directly to its constructor.\n   However, in my opinion, it is preferable to use a separate class.\n\u003cdetails\u003e\n\u003cbase target=\"_blank\"\u003e\n\u003csummary\u003eShow code...\u003c/summary\u003e\n   \n```abap\nCLASS lcl_context DEFINITION FINAL.\n  PUBLIC SECTION.\n    INTERFACES if_serializable_object.\n\n    TYPES: \n      BEGIN OF ty_params,\n        param TYPE i,\n      END OF ty_params.\n\n    METHODS: \n      constructor IMPORTING is_params TYPE ty_params,\n      get RETURNING VALUE(rs_params) TYPE ty_params.\n\n  PRIVATE SECTION.\n    DATA ms_params TYPE ty_params.\nENDCLASS.\n\nCLASS lcl_context IMPLEMENTATION.\n  METHOD constructor.\n    ms_params = is_params.\n  ENDMETHOD.\n\n  METHOD get.\n    rs_params = ms_params.\n  ENDMETHOD.\nENDCLASS.\n```\n\u003c/details\u003e\n\n2. **lcl_task**, describes an object *Task*. Contains business logic (in our case, raising a number to the power of 2).\n   Note that the **lcl_task** class inherits from the **zcl_capi_abstract_task** class and overrides the **zif_capi_callable~call** method.\n\u003cdetails\u003e\n\u003cbase target=\"_blank\"\u003e\n\u003csummary\u003eShow code...\u003c/summary\u003e\n   \n```abap\nCLASS lcl_task DEFINITION INHERITING FROM zcl_capi_abstract_task FINAL.\n  PUBLIC SECTION.\n\n    METHODS: \n      constructor IMPORTING io_context TYPE REF TO lcl_context,\n      zif_capi_callable~call REDEFINITION.\n\n  PRIVATE SECTION.\n    DATA mo_context TYPE REF TO lcl_context.\n    DATA mv_res TYPE i.\nENDCLASS.\n\nCLASS lcl_task IMPLEMENTATION.\n  METHOD constructor.\n    super-\u003econstructor( ).\n    mo_context = io_context.\n  ENDMETHOD.\n\n  METHOD zif_capi_callable~call.\n   \n    DATA(ls_params) = mo_context-\u003eget( ).\n    mv_res = ls_params-param ** 2.\n    \n    ro_result = new lcl_result( iv_param  = ls_params-param\n                                iv_result = mv_res ).\n  ENDMETHOD.\nENDCLASS.\n```\n\u003c/details\u003e\n   \n3. **lcl_result** describes *the result* of the task.\n   This class must implement the **if_serializable_object** interface. Otherwise, you can describe it in any way you want.\n\n\u003cdetails\u003e\n\u003cbase target=\"_blank\"\u003e\n\u003csummary\u003eShow code...\u003c/summary\u003e\n   \n```abap\nCLASS lcl_result DEFINITION FINAL.\n  PUBLIC SECTION.\n    INTERFACES if_serializable_object.\n\n    METHODS: \n      constructor IMPORTING iv_param  TYPE i\n                            iv_result TYPE i,\n      get RETURNING VALUE(rv_result) TYPE string.\n\n  PRIVATE SECTION.\n    DATA mv_param TYPE i.\n    DATA mv_result TYPE i.\nENDCLASS.\n\nCLASS lcl_result IMPLEMENTATION.\n  METHOD constructor.\n    mv_param = iv_param.\n    mv_result = iv_result.\n  ENDMETHOD.\n\n  METHOD get.\n    rv_result = |{ mv_param } -\u003e { mv_result }|.\n  ENDMETHOD.\nENDCLASS.\n```\n\u003c/details\u003e\n\n**Attention:**  \nObjects of the **lcl_task** and **lcl_result** classes are serialized/deserialized at runtime, so avoid using static attributes.\nStatic attributes belong to the class, not the object. Their contents will be lost after serialization/deserialization.\n\nSo, the objects *Context*, *Task*, and *Result* are described.\nNow, let's have a look at example:\n\n\u003cdetails\u003e\n\u003cbase target=\"_blank\"\u003e\n\u003csummary\u003eShow code...\u003c/summary\u003e\n   \n```abap\n    CONSTANTS lc_server_group TYPE rfcgr VALUE 'parallel_generators'.\n    DATA lo_result TYPE REF TO lcl_result.\n\n    \" Create collection of tasks\n    DATA(lo_tasks) = NEW zcl_capi_collection( ).\n\n    DO 10 TIMES.\n   \n      DATA(lo_context) = NEW lcl_context( VALUE lcl_context=\u003ety_params( param = sy-index ) ).\n      DATA(lo_task) = NEW lcl_task( lo_context ).\n      lo_tasks-\u003ezif_capi_collection~add( lo_task ).\n   \n    ENDDO.\n\n    DATA(lo_message_handler) = NEW zcl_capi_message_handler( ).\n    DATA(lv_max_no_of_tasks) = zcl_capi_thread_pool_executor=\u003emax_no_of_tasks( lc_server_group ).\n  \n    DATA(lo_executor) = zcl_capi_executors=\u003enew_fixed_thread_pool( iv_server_group         = lc_server_group\n                                                                   iv_n_threads            = lv_max_no_of_tasks\n                                                                   io_capi_message_handler = lo_message_handler ).\n    TRY.\n        DATA(lo_results) = lo_executor-\u003ezif_capi_executor_service~invoke_all( lo_tasks ).\n\n        IF lo_message_handler-\u003ezif_capi_message_handler~has_messages( ) = abap_false.\n\n          DATA(lo_results_iterator) = lo_results-\u003eget_iterator( ).\n\n          WHILE lo_results_iterator-\u003ehas_next( ).\n            lo_result ?= lo_results_iterator-\u003enext( ).\n            WRITE: / lo_result-\u003eget( ).\n          ENDWHILE.\n\n        ENDIF.\n\n      CATCH zcx_capi_tasks_invocation INTO DATA(lo_capi_tasks_invocation).\n        WRITE lo_capi_tasks_invocation-\u003eget_text( ).\n    ENDTRY.\n```\n\u003c/details\u003e\n   \n1. First, create *Tasks collection* **lo_tasks**\n2. Next, create a *Task* **lo_task** and add it to the *Tasks collection* **lo_tasks**\n3. Create a message handler **lo_message_handler** (optional)\n4. Now we come to the most important part of the API of the “executor service” concept. The executor asynchronously executes the tasks passed to it.  \n   In the example, we call the static method **zcl_capi_executors=\u003enew_fixed_thread_pool**, which returns a lo_executor with a fixed number of threads. This method has 4 parameters:\n\n| Parameter name              | Optional | Description                                                   |\n| :-------------------------- | :------: | :-------------------------------------------------------------|\n| iv_server_group             |          | server group (tcode: RZ12)                                    |\n| iv_max_no_of_tasks          |          | maximum number of parallel tasks                            |\n| iv_no_resubmission_on_error |          | flag \"**true**\" - don't restart the task in case of an error  |\n| io_capi_message_handler     |    X     | an object that will contain error messages (if they occurred) |\n\n  The **lo_executor** object has only one interface method **zif_capi_executor_service~invoke_all ()**, which takes as input a **collection of tasks** and returns a **collection of results** **lo_results** (the approach was taken from **java.util.concurrent.***).\n\n5. The *Collection of results* **lo_results** has an iterator, using which we easily get the **lo_result** and call the **get()** method from them.\n\nAs a result, we did't have to create an RFC functional module, describe the parallelization process, etc.\nAll we did was describe what the *Task* and *Result* are.\n\n**Result of execution:**\n\n![result](https://github.com/victorizbitskiy/zconcurrency_api/blob/main/docs/img/result.png)\n\nAn example of using the `ABAP Concurrency API` can be found in the **ZCONCURRENCY_API_EXAMPLE** report.\n\n## Using in the HCM module\nTo simplify the work with the ABAP Concurrency API in the HCM module, it is proposed to use the implementation of the \u003ca href=\"https://en.wikipedia.org/wiki/Facade_pattern#:~:text=The%20facade%20pattern%20(also%20spelled,complex%20underlying%20or%20structural%20code.\"\u003eFacade\u003c/a\u003e structural pattern - ZCAPI_FACADE_HCM package. The Facade design pattern encapsulates the breakdown of personnel numbers into batches, the creation of *Task* objects, and the retrieval of the result.\n\nLet's consider a simple task:\n\n*Get the full name of employees by personnel numbers.*\n\nFirst, we will also create 3 classes: *Context*, *Task* and *Result*.\n\n1. **lcl_contex**, an object of this class will encapsulate the task parameters. Note that the *lcl_contex* class must inherit from the abstract class **zcl_capi_facade_hcm_abstr_cntx**. When implementing, you must override the *constructor* method.\n\u003cdetails\u003e\n\u003cbase target=\"_blank\"\u003e\n\u003csummary\u003eShow code...\u003c/summary\u003e\n  \n  ```abap\n  CLASS lcl_context DEFINITION INHERITING FROM zcl_capi_facade_hcm_abstr_cntx FINAL.\n  PUBLIC SECTION.\n\n    TYPES:\n      BEGIN OF ty_params,\n        begda TYPE d,\n        endda TYPE d,\n      END OF ty_params.\n\n    METHODS:\n      constructor IMPORTING is_params TYPE ty_params,\n      get_params RETURNING VALUE(rs_params) TYPE ty_params.\n\n  PRIVATE SECTION.\n    DATA: ms_params TYPE ty_params.\n\nENDCLASS.\n\nCLASS lcl_context IMPLEMENTATION.\n  METHOD constructor.\n    super-\u003econstructor( ).\n    ms_params = is_params.\n  ENDMETHOD.\n\n  METHOD get_params.\n    rs_params = ms_params.\n  ENDMETHOD.\nENDCLASS.\n  ```\n\u003c/details\u003e\n\n2. **lcl_task**, describes the *Task* object. Contains business logic (getting full name by personnel number of an employee).\n   The **lcl_task** class must inherit from the **zcl_capi_facade_hcm_abstr_task** class. You must implement the *constructor* method and override the *zif_capi_callable~call* method.\n\u003cdetails\u003e\n\u003cbase target=\"_blank\"\u003e\n\u003csummary\u003eShow code...\u003c/summary\u003e\n  \n```abap\nCLASS lcl_task DEFINITION INHERITING FROM zcl_capi_facade_hcm_abstr_task FINAL.\n  PUBLIC SECTION.\n\n    METHODS:\n      constructor IMPORTING io_context TYPE REF TO zcl_capi_facade_hcm_abstr_cntx,\n      zif_capi_callable~call REDEFINITION.\n\n  PRIVATE SECTION.\n    DATA ms_params TYPE lcl_context=\u003ety_params.\n\nENDCLASS.\n\nCLASS lcl_task IMPLEMENTATION.\n  METHOD constructor.\n    DATA lo_context TYPE REF TO lcl_context.\n\n    \" Set Pernrs numbers to mt_pernrs of Task\n    super-\u003econstructor( io_context ).\n\n    \" Set Context parameters\n    lo_context ?= io_context.\n    ms_params = lo_context-\u003eget_params( ).\n\n  ENDMETHOD.\n\n  METHOD zif_capi_callable~call.\n   \n    DATA lt_employees TYPE lcl_result=\u003ety_t_employees.\n    DATA ls_employees LIKE LINE OF lt_employees.\n          \n    \" Simulation of reading the full name of employees by their personnel numbers.\n    \" The ms_params attribute is available here.\n    \" We won't be using it in this example, but you can.\n\n    LOOP AT mt_pernrs ASSIGNING FIELD-SYMBOL(\u003cls_pernr\u003e).\n      ls_employees-pernr = \u003cls_pernr\u003e-low.\n\n      CASE \u003cls_pernr\u003e-low.\n        WHEN 00000001.\n          ls_employees-ename = 'John Doe 1'.\n        WHEN 00000002.\n          ls_employees-ename = 'John Doe 2'.\n        WHEN 00000003.\n          ls_employees-ename = 'John Doe 3'.\n        WHEN 00000004.\n          ls_employees-ename = 'John Doe 4'.\n        WHEN 00000005.\n          ls_employees-ename = 'John Doe 5'.\n        WHEN 00000006.\n          ls_employees-ename = 'John Doe 6'.\n        WHEN 00000007.\n          ls_employees-ename = 'John Doe 7'.\n        WHEN 00000008.\n          ls_employees-ename = 'John Doe 8'.\n        WHEN 00000009.\n          ls_employees-ename = 'John Doe 9'.\n        WHEN 00000010.\n          ls_employees-ename = 'John Doe 10'.\n        WHEN OTHERS.\n      ENDCASE.\n\n      INSERT ls_employees INTO TABLE lt_employees.\n    ENDLOOP.\n\n    ro_result = NEW lcl_result( lt_employees ).\n\n  ENDMETHOD.\nENDCLASS.\n```\n\n\u003c/details\u003e\n\n3. **lcl_result** describes *Result* of task execution.\nThis class must implement the **zif_capi_facade_hcm_result** interface. Otherwise, you can describe it in any way.\n\n\u003cdetails\u003e\n\u003cbase target=\"_blank\"\u003e\n\u003csummary\u003eShow code...\u003c/summary\u003e\n  \n```abap\nCLASS lcl_result DEFINITION FINAL.\n  PUBLIC SECTION.\n    INTERFACES zif_capi_facade_hcm_result.\n\n    TYPES:\n      BEGIN OF ty_employees,\n        pernr TYPE n LENGTH 8,\n        ename TYPE string,\n      END OF ty_employees,\n\n      ty_t_employees TYPE STANDARD TABLE OF ty_employees WITH KEY pernr.\n\n    METHODS constructor IMPORTING it_employees TYPE ty_t_employees.\n\n  PRIVATE SECTION.\n    DATA mt_employees TYPE ty_t_employees.\n\nENDCLASS.\n\nCLASS lcl_result IMPLEMENTATION.\n  METHOD constructor.\n    mt_employees = it_employees.\n  ENDMETHOD.\n\n  METHOD zif_capi_facade_hcm_result~get.\n    et_result = mt_employees.\n  ENDMETHOD.                    \"get\nENDCLASS.\n```\n\u003c/details\u003e\n\n**Attention:**\nClass objects **lcl_task** and **lcl_result** are serialized/deserialized at runtime, so avoid using static attributes.\n\nSo, the objects *Context*, *Task*, and *Result* are described.\nNow, let's have a look at example:\n\n\u003cdetails\u003e\n\u003cbase target=\"_blank\"\u003e\n\u003csummary\u003eShow code...\u003c/summary\u003e\n  \n```abap \n    DATA lt_employees TYPE lcl_result=\u003ety_t_employees.\n\n    \" 2 Pernr number per task. For example only.\n    \" '200' will be fine.\n    DATA(lv_package_size) = 2.\n   \n    DATA(ls_params) = VALUE lcl_context=\u003ety_params( begda = sy-datum\n                                                    endda = sy-datum ).\n    DATA(lo_context) = NEW lcl_context( ls_params ).\n\n    DATA(lo_capi_facade_hcm) = NEW zcl_capi_facade_hcm( io_context         = lo_context\n                                                        it_pernrs          = gt_pernrs\n                                                        iv_task_class_name = 'LCL_TASK'\n                                                        iv_package_size    = lv_package_size ).\n    TRY.\n        lo_capi_facade_hcm-\u003eexecute( IMPORTING et_result = lt_employees ).\n\n        WRITE `PERNR    ENAME`.\n        LOOP AT lt_employees ASSIGNING FIELD-SYMBOL(\u003cls_employees\u003e).\n          WRITE: / \u003cls_employees\u003e-pernr, \u003cls_employees\u003e-ename.\n        ENDLOOP.\n\n      CATCH zcx_capi_tasks_invocation INTO DATA(lo_capi_tasks_invocation).\n        WRITE lo_capi_tasks_invocation-\u003eget_text( ).\n    ENDTRY.\n```\n\u003c/details\u003e\n\n1. First, create *Contexts* **lo_context**, which contains parameters for launching *Tasks*.\n2. Next, create *Facade* **lo_capi_facade_hcm**, the constructor of which has 4 parameters:\n\n| Parameter name              | Description                                                         |\n| :-------------------------- | :-------------------------------------------------------------------|\n| io_context                  | This is an object containing the parameters for starting the task   |\n| it_pernrs                   | This is the personnel number range                                  |\n| iv_task_class_name          | The name of the Task class.                                         |\n| iv_package_size             | This is the number of personnel numbers per task.                   |\n\n3. Call the *execute()* method on the **lo_capi_facade_hcm** object, which starts tasks for parallel execution and returns the result.\n\nThe maximum number of running in parallel tasks is calculated as 40% of the number of free dialog processes (DIA, sm50).\nThat's all you need to do.\n\n**Result of execution:**\n\n![result](https://github.com/victorizbitskiy/zconcurrency_api/blob/main/docs/img/result%20HCM.png)\n\nThe considered example of using the Facade for the `ABAP Concurrency API` can be found in the **ZCAPI_FACADE_HCM_EXAMPLE** report.\n\n## Diagrams\n\u003cdetails\u003e\n  \u003csummary\u003eUML Class Diagram ABAP Concurrency API\u003c/summary\u003e\n   \u003cp\u003e\u003ca target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/victorizbitskiy/zconcurrency_api/blob/main/docs/img/UML%20Class%20Dia.png\"\u003e\u003cimg src=\"https://github.com/victorizbitskiy/zconcurrency_api/blob/main/docs/img/UML%20Class%20Dia.png\" alt=\"UML Class Diagram\" style=\"max-width:100%;\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n  \u003csummary\u003eUML Class Diagram ABAP Concurrency API for HCM module\u003c/summary\u003e\n   \u003cp\u003e\u003ca target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/victorizbitskiy/zconcurrency_api/blob/main/docs/img/UML%20Class%20Dia%20ABAP%20CAPI%20for%20HCM.png\"\u003e\u003cimg src=\"https://github.com/victorizbitskiy/zconcurrency_api/blob/main/docs/img/UML%20Class%20Dia%20ABAP%20CAPI%20for%20HCM.png\" alt=\"UML Class Diagram HCM\" style=\"max-width:100%;\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n  \u003csummary\u003eUML Sequence Diagram \u003c/summary\u003e\n   \u003cp\u003e\u003ca target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/victorizbitskiy/zconcurrency_api/blob/main/docs/img/UML%20Sequence%20Dia.png\"\u003e\u003cimg src=\"https://github.com/victorizbitskiy/zconcurrency_api/blob/main/docs/img/UML%20Sequence%20Dia.png\" alt=\"UML Sequence Diagram\" style=\"max-width:100%;\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003c/details\u003e\n\n## Dependencies\nSPTA package required.\n\n## Limitations:\nBatch input is not supported.\nThis limitation is related to the use of SPTA Framework.  \nSee the note [734205](https://launchpad.support.sap.com/#/notes/734205) and [710920](https://launchpad.support.sap.com/#/notes/710920) for details.\n\n## How to contribute\n[This instruction](https://docs.abapgit.org/guide-contributing.html) will help you.\n  \n## Got questions?\nIf you have questions or general suggestions, don't hesitate to submit a new [(GitHub issue)](https://github.com/victorizbitskiy/zconcurrency_api/issues/new).\n  \n## Logo\nProject logo \u003ca href=\"https://ru.freepik.com/macrovector\"\u003edesigned by macrovector/Freepik\u003c/a\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvictorizbitskiy%2Fzconcurrency_api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvictorizbitskiy%2Fzconcurrency_api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvictorizbitskiy%2Fzconcurrency_api/lists"}