Repository: caikit/caikit
Pull request #535 (2023-10-19 15:59:44)

Sort Modules in inference rpcs generation
<!--  Thanks for sending a pull request!  Here are some tips for you:
1. Make sure to read the Contributing Guide before submitting your PR: https://github.com/caikit/caikit/blob/main/CONTRIBUTING.md
2. If this PR closes another issue, add 'closes #<issue number>' somewhere in the PR summary. GitHub will automatically close that issue when this PR gets merged. Alternatively, adding 'refs #<issue number>' will not close the issue, but help provide the reviewer more context.-->

**What this PR does / why we need it**:

When generating inference rpcs, we use `modules` as a set, not a list, so the order of modules could be undeterministic. 

This PR sorts that modules list by Module ID so the list is fixed and deterministic.

Ex: SampleTaskRequest contains inference signatures from ListModule, SampleModule, PrimitiveSampleModule. Because this is a set of modules, it depends on which module is processed first, SampleTaskRequest will have different field ordering.

May be one of the fixes for https://github.com/caikit/caikit-nlp/issues/237.

**Special notes for your reviewer**:

**If applicable**:
- [ ] this PR contains documentation
- [x] this PR contains unit tests
- [ ] this PR has been tested for backwards compatibility



Patch:
diff --git a/caikit/runtime/service_generation/create_service.py b/caikit/runtime/service_generation/create_service.py
index 2bf369b4..debbd231 100644
--- a/caikit/runtime/service_generation/create_service.py
+++ b/caikit/runtime/service_generation/create_service.py
@@ -165,6 +165,8 @@ def _group_modules_by_task(
     excluded_tasks: List[Type[TaskBase]],
 ) -> Dict[Type[TaskBase], List[CaikitMethodSignature]]:
     task_groups = {}
+    # Sort modules so the order of modules processed is deterministic
+    modules = sorted(modules, key=lambda x: x.MODULE_ID)
     for ck_module in modules:
         for task_class in ck_module.tasks:
             if (


Test patch:
diff --git a/tests/runtime/service_generation/test_create_service.py b/tests/runtime/service_generation/test_create_service.py
index b3301db1..b930343d 100644
--- a/tests/runtime/service_generation/test_create_service.py
+++ b/tests/runtime/service_generation/test_create_service.py
@@ -265,6 +265,32 @@ def test_create_inference_rpcs_for_multiple_modules_of_same_type():
     assert sample_lib.modules.other_task.OtherModule in rpcs[-1].module_list
 
 
+def test_create_inference_rpcs_respects_sorted_order_by_module_id():
+    module_list = [
+        sample_lib.modules.sample_task.ListModule,  # 00af2203-0405-0607-0263-0a0b02dd0c2f
+        sample_lib.modules.sample_task.SampleModule,  # 00110203-0405-0607-0809-0a0b02dd0e0f
+        sample_lib.modules.sample_task.SamplePrimitiveModule,  # 00112233-0405-0607-0809-0a0b02dd0e0f
+    ]
+    rpcs = create_inference_rpcs(module_list)
+
+    # 3 RPCs, SampleModule, SamplePrimitiveModule and ListModule have task SampleTask with 3 flavors for
+    # streaming
+    assert len(rpcs) == 3
+    assert sample_lib.modules.sample_task.SampleModule in rpcs[0].module_list
+    assert sample_lib.modules.sample_task.SamplePrimitiveModule in rpcs[0].module_list
+    assert sample_lib.modules.sample_task.SampleModule in rpcs[1].module_list
+    assert sample_lib.modules.sample_task.SampleModule in rpcs[2].module_list
+    assert sample_lib.modules.sample_task.ListModule in rpcs[0].module_list
+
+    # check for alphabetical order of modules in rpcs[0] by Module ID
+    # this should always be deterministic
+    assert sample_lib.modules.sample_task.SampleModule == rpcs[0].module_list[0]
+    assert (
+        sample_lib.modules.sample_task.SamplePrimitiveModule == rpcs[0].module_list[1]
+    )
+    assert sample_lib.modules.sample_task.ListModule == rpcs[0].module_list[-1]
+
+
 def test_create_inference_rpcs_removes_modules_with_no_task():
     module_list = [
         sample_lib.modules.sample_task.SampleModule,  # has a task, has 3 streaming flavors