@@ -459,6 +459,135 @@ async def _start_wf_and_nexus_op(
459
459
return caller_wf_handle , handler_wf_handle
460
460
461
461
462
+ @nexusrpc .interface .service
463
+ class MyServiceInterfaceWithoutNameOverride :
464
+ my_op : nexusrpc .interface .Operation [None , str ]
465
+
466
+
467
+ @nexusrpc .interface .service (name = "my-service-interface-🌈" )
468
+ class MyServiceInterfaceWithNameOverride :
469
+ my_op : nexusrpc .interface .Operation [None , str ]
470
+
471
+
472
+ @nexusrpc .handler .service (interface = MyServiceInterfaceWithoutNameOverride )
473
+ class MyServiceImplWithoutNameOverride :
474
+ @nexusrpc .handler .sync_operation
475
+ async def my_op (
476
+ self , input : None , options : nexusrpc .handler .StartOperationOptions
477
+ ) -> str :
478
+ return "from service impl with interface"
479
+
480
+
481
+ @nexusrpc .handler .service (name = "my-service-impl-🌈" )
482
+ class MyServiceImplWithNameOverride :
483
+ @nexusrpc .handler .sync_operation
484
+ async def my_op (
485
+ self , input : None , options : nexusrpc .handler .StartOperationOptions
486
+ ) -> str :
487
+ return "from service impl with name override"
488
+
489
+
490
+ class NameOverride (StrEnum ):
491
+ YES = "yes"
492
+ NO = "no"
493
+
494
+
495
+ @workflow .defn
496
+ class MyServiceInterfaceAndImplCallerWorkflow :
497
+ @workflow .run
498
+ async def run (
499
+ self ,
500
+ caller_reference : CallerReference ,
501
+ name_override : NameOverride ,
502
+ task_queue : str ,
503
+ ) -> str :
504
+ service_cls = {
505
+ (
506
+ CallerReference .INTERFACE ,
507
+ NameOverride .YES ,
508
+ ): MyServiceInterfaceWithNameOverride ,
509
+ (
510
+ CallerReference .INTERFACE ,
511
+ NameOverride .NO ,
512
+ ): MyServiceInterfaceWithoutNameOverride ,
513
+ (
514
+ CallerReference .IMPLEMENTATION ,
515
+ NameOverride .YES ,
516
+ ): MyServiceImplWithNameOverride ,
517
+ (
518
+ CallerReference .IMPLEMENTATION ,
519
+ NameOverride .NO ,
520
+ ): MyServiceImplWithoutNameOverride ,
521
+ }[caller_reference , name_override ]
522
+ nexus_client = workflow .NexusClient (
523
+ service = service_cls ,
524
+ endpoint = make_nexus_endpoint_name (task_queue ),
525
+ )
526
+ return await nexus_client .execute_operation (service_cls .my_op , None )
527
+
528
+
529
+ # TODO(dan): make it possible to refer to an impl that doesn't itself refer to an interface in its decorator
530
+ # TODO(dan): allow decorator to be used without calling it
531
+ # TODO(dan): check missing decorator behavior
532
+
533
+
534
+ async def test_service_interface_and_implementation_names (client : Client ):
535
+ task_queue = str (uuid .uuid4 ())
536
+ async with Worker (
537
+ client ,
538
+ nexus_services = [
539
+ MyServiceImplWithoutNameOverride (),
540
+ MyServiceImplWithNameOverride (),
541
+ ],
542
+ workflows = [MyServiceInterfaceAndImplCallerWorkflow ],
543
+ task_queue = task_queue ,
544
+ workflow_runner = UnsandboxedWorkflowRunner (),
545
+ ):
546
+ await create_nexus_endpoint (task_queue , client )
547
+ assert (
548
+ await client .execute_workflow (
549
+ MyServiceInterfaceAndImplCallerWorkflow .run ,
550
+ args = (CallerReference .INTERFACE , NameOverride .YES , task_queue ),
551
+ id = str (uuid .uuid4 ()),
552
+ task_queue = task_queue ,
553
+ )
554
+ == "from service interface with name override"
555
+ )
556
+ assert (
557
+ await client .execute_workflow (
558
+ MyServiceInterfaceAndImplCallerWorkflow .run ,
559
+ args = (CallerReference .INTERFACE , NameOverride .NO , task_queue ),
560
+ id = str (uuid .uuid4 ()),
561
+ task_queue = task_queue ,
562
+ )
563
+ == "from service interface without name override"
564
+ )
565
+ assert (
566
+ await client .execute_workflow (
567
+ MyServiceInterfaceAndImplCallerWorkflow .run ,
568
+ args = (CallerReference .IMPLEMENTATION , NameOverride .YES , task_queue ),
569
+ id = str (uuid .uuid4 ()),
570
+ task_queue = task_queue ,
571
+ )
572
+ == "from service impl with interface and name override"
573
+ )
574
+ assert (
575
+ await client .execute_workflow (
576
+ MyServiceInterfaceAndImplCallerWorkflow .run ,
577
+ args = (CallerReference .IMPLEMENTATION , NameOverride .NO , task_queue ),
578
+ id = str (uuid .uuid4 ()),
579
+ task_queue = task_queue ,
580
+ )
581
+ == "from service impl with interface but without name override"
582
+ )
583
+
584
+
585
+ # TODO(dan): test invalid service interface implementations
586
+ # TODO(dan): test service impls and interfaces with and without names, conflicting names, etc.
587
+ # TODO(dan): test impl used without interface
588
+ # TODO(dan): test empty service impl/interface names
589
+
590
+
462
591
def make_nexus_endpoint_name (task_queue : str ) -> str :
463
592
# Create endpoints for different task queues without name collisions.
464
593
return f"nexus-endpoint-{ task_queue } "
0 commit comments