Repository: ray-project/ray

Issue:
[Core] Submission-time task names.
<!--Please include [tune], [rllib], [autoscaler] etc. in the issue title if relevant-->

### Feature Request

Allow the user to specify submission-time task names, such that the task name is used as the process title (for displaying in the dashboard and debugging) and possibly other areas (e.g. core worker stats). Using the task function name as the user-friendly identifier results in poor UX when many tasks are executed using the same remote function, especially when there exists a semantically meaningful name that could be attached to the task at submission time.

### API and Semantics

The user can specify a task name at submission time:
```python
@ray.remote
def foo(x):
    return x + 1

foo.options(name="my_special_foo").remote(1)
```
Unlike Ray actor names, this would **not** "detach" the task, and global uniqueness of these task names would **not** be enforced. Given the existing semantics for `actor.options(name="foo").remote()`, I'm imagining that this new task name option would only apply for actor and non-actor tasks, not for actor creation.

When viewing the machine view of the Ray dashboard, the current task (in the workers/PID column) for a given core worker would be given by this task name, if set. The task name could also be included in other metrics/stats payloads, such as the core worker stats.

### Possible Implementation

I think that this semantically meaningful task name should be easy to propagate if there's a dedicated field on the `TaskSpec`. If the user supplies a `name` at task submission time, the `task_name` field is set to that; if not, it's set to the task function's name, the current behavior.

Flow - setting field in task spec + using said field to set proctitle:
1. Add a `task_name` field to the `TaskSpec` [class](https://github.com/ray-project/ray/blob/0178d6318ead643fff6d9ed873c88f71fdac52e7/src/ray/common/task/task_spec.h#L30-L216)/[proto](https://github.com/ray-project/ray/blob/fe6daef85e1f3cd2aef12b39487124a6e2dcc2b9/src/ray/protobuf/common.proto#L147-L189) and to the [`TaskOptions` class](https://github.com/ray-project/ray/blob/0178d6318ead643fff6d9ed873c88f71fdac52e7/src/ray/core_worker/common.h#L54-L64).
2. Properly set it on the task spec in [`CoreWorker::SubmitTask`](https://github.com/ray-project/ray/blob/0aec4cbccb5862a7808f98b90696236da9e2a03e/src/ray/core_worker/core_worker.cc#L1257-L1287) and [`CoreWorker::SubmitActorTask`](https://github.com/ray-project/ray/blob/0aec4cbccb5862a7808f98b90696236da9e2a03e/src/ray/core_worker/core_worker.cc#L1398-L1436) to either the user-provided `task_name` if given or set it to the function's name if not (current behavior).
3. Pull the `task_name` off of the `TaskSpec` class in [`CoreWorker::ExecuteTask`](https://github.com/ray-project/ray/blob/0aec4cbccb5862a7808f98b90696236da9e2a03e/src/ray/core_worker/core_worker.cc#L1635-L1757) and pass to language-specific task execution handler.
4. Use said `task_name` to [set the proctitle in the language-specific task execution handlers](https://github.com/ray-project/ray/blob/0aec4cbccb5862a7808f98b90696236da9e2a03e/python/ray/_raylet.pyx#L389).

### Concerns/Open Questions

1. Should the submission-time task name be appended or prepended to the function name, yielding something like `some_module.some_func:{task_name}` or `{task_name}:some_module.some_func`, instead of replacing the function name? Or should the user be expected to craft such a task name in their code and use _that_ as the `.options(name=task_name)` argument if that's what they want? I'm thinking the latter, but having to do that crafting for actor methods may be annoying.
2. Will this be confusing given the existence of named actors and the already established semantics thereof? Should a similar concept be provided for actors, and if so, how could we delineate between detached actors and named actors?


Discussion:
Btw, from 1.0 (the next version), you can name an actor that is not detached! 

Resolving patch:
diff --git a/python/ray/actor.py b/python/ray/actor.py
--- a/python/ray/actor.py
+++ b/python/ray/actor.py
@@ -100,7 +100,27 @@ def __call__(self, *args, **kwargs):
     def remote(self, *args, **kwargs):
         return self._remote(args, kwargs)
 
-    def _remote(self, args=None, kwargs=None, num_returns=None):
+    def options(self, **options):
+        """Convenience method for executing an actor method call with options.
+
+        Same arguments as func._remote(), but returns a wrapped function
+        that a non-underscore .remote() can be called on.
+
+        Examples:
+            # The following two calls are equivalent.
+            >>> actor.my_method._remote(args=[x, y], name="foo", num_returns=2)
+            >>> actor.my_method.options(name="foo", num_returns=2).remote(x, y)
+        """
+
+        func_cls = self
+
+        class FuncWrapper:
+            def remote(self, *args, **kwargs):
+                return func_cls._remote(args=args, kwargs=kwargs, **options)
+
+        return FuncWrapper()
+
+    def _remote(self, args=None, kwargs=None, name="", num_returns=None):
         if num_returns is None:
             num_returns = self._num_returns
 
@@ -112,6 +132,7 @@ def invocation(args, kwargs):
                 self._method_name,
                 args=args,
                 kwargs=kwargs,
+                name=name,
                 num_returns=num_returns)
 
         # Apply the decorator if there is one.
@@ -317,8 +338,10 @@ def _ray_from_modified_class(cls, modified_class, class_id, max_restarts,
                                  max_task_retries, num_cpus, num_gpus, memory,
                                  object_store_memory, resources):
         for attribute in [
-                "remote", "_remote", "_ray_from_modified_class",
-                "_ray_from_function_descriptor"
+                "remote",
+                "_remote",
+                "_ray_from_modified_class",
+                "_ray_from_function_descriptor",
         ]:
             if hasattr(modified_class, attribute):
                 logger.warning("Creating an actor from class "
@@ -679,6 +702,7 @@ def _actor_method_call(self,
                            method_name,
                            args=None,
                            kwargs=None,
+                           name="",
                            num_returns=None):
         """Method execution stub for an actor handle.
 
@@ -691,6 +715,7 @@ def _actor_method_call(self,
             method_name: The name of the actor method to execute.
             args: A list of arguments for the actor method.
             kwargs: A dictionary of keyword arguments for the actor method.
+            name (str): The name to give the actor method call task.
             num_returns (int): The number of return values for the method.
 
         Returns:
@@ -724,7 +749,7 @@ def _actor_method_call(self,
 
         object_refs = worker.core_worker.submit_actor_task(
             self._ray_actor_language, self._ray_actor_id, function_descriptor,
-            list_args, num_returns, self._ray_actor_method_cpus)
+            list_args, name, num_returns, self._ray_actor_method_cpus)
 
         if len(object_refs) == 1:
             object_refs = object_refs[0]
diff --git a/python/ray/remote_function.py b/python/ray/remote_function.py
--- a/python/ray/remote_function.py
+++ b/python/ray/remote_function.py
@@ -152,7 +152,8 @@ def _remote(self,
                 resources=None,
                 max_retries=None,
                 placement_group=None,
-                placement_group_bundle_index=-1):
+                placement_group_bundle_index=-1,
+                name=""):
         """Submit the remote function for execution."""
         worker = ray.worker.global_worker
         worker.check_connected()
@@ -212,7 +213,7 @@ def invocation(args, kwargs):
                     "Cross language remote function " \
                     "cannot be executed locally."
             object_refs = worker.core_worker.submit_task(
-                self._language, self._function_descriptor, list_args,
+                self._language, self._function_descriptor, list_args, name,
                 num_returns, resources, max_retries, placement_group.id,
                 placement_group_bundle_index)
 


Test patch:
diff --git a/java/test/src/main/java/io/ray/test/TaskNameTest.java b/java/test/src/main/java/io/ray/test/TaskNameTest.java
new file mode 100644
--- /dev/null
+++ b/java/test/src/main/java/io/ray/test/TaskNameTest.java
@@ -0,0 +1,19 @@
+package io.ray.test;
+
+import io.ray.api.Ray;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/** Task Name Test. */
+public class TaskNameTest extends BaseTest {
+
+  private static int testFoo() {
+    return 0;
+  }
+
+  /** Test setting task name at task submission time. */
+  @Test
+  public void testSetName() {
+    Assert.assertEquals(0, (int) Ray.task(TaskNameTest::testFoo).setName("foo").remote().get());
+  }
+}
diff --git a/python/ray/tests/test_actor.py b/python/ray/tests/test_actor.py
--- a/python/ray/tests/test_actor.py
+++ b/python/ray/tests/test_actor.py
@@ -14,6 +14,10 @@
 import ray.test_utils
 import ray.cluster_utils
 
+# NOTE: We have to import setproctitle after ray because we bundle setproctitle
+# with ray.
+import setproctitle
+
 
 def test_caching_actors(shutdown_only):
     # Test defining actors before ray.init() has been called.
@@ -673,6 +677,33 @@ def method3(self):
     assert ray.get([id3a, id3b, id3c]) == [1, 2, 3]
 
 
+def test_options_num_returns(ray_start_regular_shared):
+    @ray.remote
+    class Foo:
+        def method(self):
+            return 1, 2
+
+    f = Foo.remote()
+
+    obj = f.method.remote()
+    assert ray.get(obj) == (1, 2)
+
+    obj1, obj2 = f.method.options(num_returns=2).remote()
+    assert ray.get([obj1, obj2]) == [1, 2]
+
+
+def test_options_name(ray_start_regular_shared):
+    @ray.remote
+    class Foo:
+        def method(self, name):
+            assert setproctitle.getproctitle() == f"ray::{name}"
+
+    f = Foo.remote()
+
+    ray.get(f.method.options(name="foo").remote("foo"))
+    ray.get(f.method.options(name="bar").remote("bar"))
+
+
 def test_define_actor(ray_start_regular_shared):
     @ray.remote
     class Test:
diff --git a/python/ray/tests/test_advanced_3.py b/python/ray/tests/test_advanced_3.py
--- a/python/ray/tests/test_advanced_3.py
+++ b/python/ray/tests/test_advanced_3.py
@@ -35,7 +35,7 @@ def attempt_to_load_balance(remote_function,
             [remote_function.remote(*args) for _ in range(total_tasks)])
         names = set(locations)
         counts = [locations.count(name) for name in names]
-        logger.info("Counts are {}.".format(counts))
+        logger.info(f"Counts are {counts}.")
         if (len(names) == num_nodes
                 and all(count >= minimum_count for count in counts)):
             break
@@ -346,6 +346,28 @@ def unique_1():
     ray.get(unique_1.remote())
 
 
+def test_ray_task_name_setproctitle(ray_start_2_cpus):
+    method_task_name = "foo"
+
+    @ray.remote
+    class UniqueName:
+        def __init__(self):
+            assert setproctitle.getproctitle() == "ray::UniqueName.__init__()"
+
+        def f(self):
+            assert setproctitle.getproctitle() == f"ray::{method_task_name}"
+
+    task_name = "bar"
+
+    @ray.remote
+    def unique_1():
+        assert task_name in setproctitle.getproctitle()
+
+    actor = UniqueName.remote()
+    ray.get(actor.f.options(name=method_task_name).remote())
+    ray.get(unique_1.options(name=task_name).remote())
+
+
 @pytest.mark.skipif(
     os.getenv("TRAVIS") is None,
     reason="This test should only be run on Travis.")
@@ -508,7 +530,7 @@ def test_invalid_unicode_in_worker_log(shutdown_only):
 
     # Wait till first worker log file is created.
     while True:
-        log_file_paths = glob.glob("{}/worker*.out".format(logs_dir))
+        log_file_paths = glob.glob(f"{logs_dir}/worker*.out")
         if len(log_file_paths) == 0:
             time.sleep(0.2)
         else:
@@ -546,13 +568,13 @@ def f(self):
 
     # Make sure no log files are in the "old" directory before the actors
     # are killed.
-    assert len(glob.glob("{}/old/worker*.out".format(logs_dir))) == 0
+    assert len(glob.glob(f"{logs_dir}/old/worker*.out")) == 0
 
     # Now kill the actors so the files get moved to logs/old/.
     [a.__ray_terminate__.remote() for a in actors]
 
     while True:
-        log_file_paths = glob.glob("{}/old/worker*.out".format(logs_dir))
+        log_file_paths = glob.glob(f"{logs_dir}/old/worker*.out")
         if len(log_file_paths) > 0:
             with open(log_file_paths[0], "r") as f:
                 assert "function f finished\n" in f.readlines()
@@ -641,7 +663,7 @@ def test_gpu_info_parsing():
     """
     constraints_dict = resource_spec._constraints_from_gpu_info(info_string)
     expected_dict = {
-        "{}V100".format(ray_constants.RESOURCE_CONSTRAINT_PREFIX): 1
+        f"{ray_constants.RESOURCE_CONSTRAINT_PREFIX}V100": 1,
     }
     assert constraints_dict == expected_dict
 
@@ -658,7 +680,7 @@ def test_gpu_info_parsing():
     """
     constraints_dict = resource_spec._constraints_from_gpu_info(info_string)
     expected_dict = {
-        "{}T4".format(ray_constants.RESOURCE_CONSTRAINT_PREFIX): 1
+        f"{ray_constants.RESOURCE_CONSTRAINT_PREFIX}T4": 1,
     }
     assert constraints_dict == expected_dict
 
diff --git a/src/ray/core_worker/test/core_worker_test.cc b/src/ray/core_worker/test/core_worker_test.cc
--- a/src/ray/core_worker/test/core_worker_test.cc
+++ b/src/ray/core_worker/test/core_worker_test.cc
@@ -226,7 +226,7 @@ bool CoreWorkerTest::WaitForDirectCallActorState(const ActorID &actor_id, bool w
 int CoreWorkerTest::GetActorPid(const ActorID &actor_id,
                                 std::unordered_map<std::string, double> &resources) {
   std::vector<std::unique_ptr<TaskArg>> args;
-  TaskOptions options{1, resources};
+  TaskOptions options{"", 1, resources};
   std::vector<ObjectID> return_ids;
   RayFunction func{Language::PYTHON, ray::FunctionDescriptorBuilder::BuildPython(
                                          "GetWorkerPid", "", "", "")};
@@ -308,7 +308,7 @@ void CoreWorkerTest::TestActorTask(std::unordered_map<std::string, double> &reso
       args.emplace_back(new TaskArgByValue(
           std::make_shared<RayObject>(buffer2, nullptr, std::vector<ObjectID>())));
 
-      TaskOptions options{1, resources};
+      TaskOptions options{"", 1, resources};
       std::vector<ObjectID> return_ids;
       RayFunction func(ray::Language::PYTHON, ray::FunctionDescriptorBuilder::BuildPython(
                                                   "MergeInputArgsAsOutput", "", "", ""));
@@ -350,7 +350,7 @@ void CoreWorkerTest::TestActorTask(std::unordered_map<std::string, double> &reso
     args.emplace_back(new TaskArgByValue(
         std::make_shared<RayObject>(buffer2, nullptr, std::vector<ObjectID>())));
 
-    TaskOptions options{1, resources};
+    TaskOptions options{"", 1, resources};
     std::vector<ObjectID> return_ids;
     RayFunction func(ray::Language::PYTHON, ray::FunctionDescriptorBuilder::BuildPython(
                                                 "MergeInputArgsAsOutput", "", "", ""));
@@ -412,7 +412,7 @@ void CoreWorkerTest::TestActorRestart(
       args.emplace_back(new TaskArgByValue(
           std::make_shared<RayObject>(buffer1, nullptr, std::vector<ObjectID>())));
 
-      TaskOptions options{1, resources};
+      TaskOptions options{"", 1, resources};
       std::vector<ObjectID> return_ids;
       RayFunction func(ray::Language::PYTHON, ray::FunctionDescriptorBuilder::BuildPython(
                                                   "MergeInputArgsAsOutput", "", "", ""));
@@ -455,7 +455,7 @@ void CoreWorkerTest::TestActorFailure(
       args.emplace_back(new TaskArgByValue(
           std::make_shared<RayObject>(buffer1, nullptr, std::vector<ObjectID>())));
 
-      TaskOptions options{1, resources};
+      TaskOptions options{"", 1, resources};
       std::vector<ObjectID> return_ids;
       RayFunction func(ray::Language::PYTHON, ray::FunctionDescriptorBuilder::BuildPython(
                                                   "MergeInputArgsAsOutput", "", "", ""));
@@ -539,12 +539,12 @@ TEST_F(ZeroNodeTest, TestTaskSpecPerf) {
   RAY_LOG(INFO) << "start creating " << num_tasks << " PushTaskRequests";
   rpc::Address address;
   for (int i = 0; i < num_tasks; i++) {
-    TaskOptions options{1, resources};
+    TaskOptions options{"", 1, resources};
     std::vector<ObjectID> return_ids;
     auto num_returns = options.num_returns;
 
     TaskSpecBuilder builder;
-    builder.SetCommonTaskSpec(RandomTaskId(), function.GetLanguage(),
+    builder.SetCommonTaskSpec(RandomTaskId(), options.name, function.GetLanguage(),
                               function.GetFunctionDescriptor(), job_id, RandomTaskId(), 0,
                               RandomTaskId(), address, num_returns, resources, resources,
                               PlacementGroupID::Nil());
@@ -587,7 +587,7 @@ TEST_F(SingleNodeTest, TestDirectActorTaskSubmissionPerf) {
     args.emplace_back(new TaskArgByValue(
         std::make_shared<RayObject>(buffer, nullptr, std::vector<ObjectID>())));
 
-    TaskOptions options{1, resources};
+    TaskOptions options{"", 1, resources};
     std::vector<ObjectID> return_ids;
     RayFunction func(ray::Language::PYTHON, ray::FunctionDescriptorBuilder::BuildPython(
                                                 "MergeInputArgsAsOutput", "", "", ""));
diff --git a/src/ray/core_worker/test/direct_task_transport_test.cc b/src/ray/core_worker/test/direct_task_transport_test.cc
--- a/src/ray/core_worker/test/direct_task_transport_test.cc
+++ b/src/ray/core_worker/test/direct_task_transport_test.cc
@@ -324,9 +324,10 @@ TaskSpecification BuildTaskSpec(const std::unordered_map<std::string, double> &r
                                 const ray::FunctionDescriptor &function_descriptor) {
   TaskSpecBuilder builder;
   rpc::Address empty_address;
-  builder.SetCommonTaskSpec(TaskID::Nil(), Language::PYTHON, function_descriptor,
-                            JobID::Nil(), TaskID::Nil(), 0, TaskID::Nil(), empty_address,
-                            1, resources, resources, PlacementGroupID::Nil());
+  builder.SetCommonTaskSpec(TaskID::Nil(), "dummy_task", Language::PYTHON,
+                            function_descriptor, JobID::Nil(), TaskID::Nil(), 0,
+                            TaskID::Nil(), empty_address, 1, resources, resources,
+                            PlacementGroupID::Nil());
   return builder.Build();
 }
 
diff --git a/src/ray/core_worker/test/mock_worker.cc b/src/ray/core_worker/test/mock_worker.cc
--- a/src/ray/core_worker/test/mock_worker.cc
+++ b/src/ray/core_worker/test/mock_worker.cc
@@ -50,8 +50,8 @@ class MockWorker {
         "",                  // driver_name
         "",                  // stdout_file
         "",                  // stderr_file
-        std::bind(&MockWorker::ExecuteTask, this, _1, _2, _3, _4, _5, _6,
-                  _7),  // task_execution_callback
+        std::bind(&MockWorker::ExecuteTask, this, _1, _2, _3, _4, _5, _6, _7,
+                  _8),  // task_execution_callback
         nullptr,        // check_signals
         nullptr,        // gc_collect
         nullptr,        // spill_objects
@@ -71,7 +71,8 @@ class MockWorker {
   void RunTaskExecutionLoop() { CoreWorkerProcess::RunTaskExecutionLoop(); }
 
  private:
-  Status ExecuteTask(TaskType task_type, const RayFunction &ray_function,
+  Status ExecuteTask(TaskType task_type, const std::string task_name,
+                     const RayFunction &ray_function,
                      const std::unordered_map<std::string, double> &required_resources,
                      const std::vector<std::shared_ptr<RayObject>> &args,
                      const std::vector<ObjectID> &arg_reference_ids,
diff --git a/src/ray/gcs/test/gcs_test_util.h b/src/ray/gcs/test/gcs_test_util.h
--- a/src/ray/gcs/test/gcs_test_util.h
+++ b/src/ray/gcs/test/gcs_test_util.h
@@ -38,9 +38,10 @@ struct Mocker {
     auto actor_id = ActorID::Of(job_id, RandomTaskId(), 0);
     auto task_id = TaskID::ForActorCreationTask(actor_id);
     auto resource = std::unordered_map<std::string, double>();
-    builder.SetCommonTaskSpec(task_id, Language::PYTHON, empty_descriptor, job_id,
-                              TaskID::Nil(), 0, TaskID::Nil(), owner_address, 1, resource,
-                              resource, PlacementGroupID::Nil());
+    builder.SetCommonTaskSpec(task_id, name + ":" + empty_descriptor->CallString(),
+                              Language::PYTHON, empty_descriptor, job_id, TaskID::Nil(),
+                              0, TaskID::Nil(), owner_address, 1, resource, resource,
+                              PlacementGroupID::Nil());
     builder.SetActorCreationTaskSpec(actor_id, max_restarts, {}, 1, detached, name);
     return builder.Build();
   }
diff --git a/src/ray/raylet/scheduling/cluster_task_manager_test.cc b/src/ray/raylet/scheduling/cluster_task_manager_test.cc
--- a/src/ray/raylet/scheduling/cluster_task_manager_test.cc
+++ b/src/ray/raylet/scheduling/cluster_task_manager_test.cc
@@ -264,7 +264,7 @@ Task CreateTask(const std::unordered_map<std::string, double> &required_resource
   TaskID id = RandomTaskId();
   JobID job_id = RandomJobId();
   rpc::Address address;
-  spec_builder.SetCommonTaskSpec(id, Language::PYTHON,
+  spec_builder.SetCommonTaskSpec(id, "dummy_task", Language::PYTHON,
                                  FunctionDescriptorBuilder::BuildPython("", "", "", ""),
                                  job_id, TaskID::Nil(), 0, TaskID::Nil(), address, 0,
                                  required_resources, {}, PlacementGroupID::Nil());
@@ -489,4 +489,4 @@ int main(int argc, char **argv) {
 }
 
 }  // namespace raylet
-}  // namespace ray
\ No newline at end of file
+}  // namespace ray
diff --git a/src/ray/raylet/task_dependency_manager_test.cc b/src/ray/raylet/task_dependency_manager_test.cc
--- a/src/ray/raylet/task_dependency_manager_test.cc
+++ b/src/ray/raylet/task_dependency_manager_test.cc
@@ -65,7 +65,7 @@ static inline Task ExampleTask(const std::vector<ObjectID> &arguments,
                                uint64_t num_returns) {
   TaskSpecBuilder builder;
   rpc::Address address;
-  builder.SetCommonTaskSpec(RandomTaskId(), Language::PYTHON,
+  builder.SetCommonTaskSpec(RandomTaskId(), "example_task", Language::PYTHON,
                             FunctionDescriptorBuilder::BuildPython("", "", "", ""),
                             JobID::Nil(), RandomTaskId(), 0, RandomTaskId(), address,
                             num_returns, {}, {}, PlacementGroupID::Nil());
diff --git a/streaming/src/test/mock_actor.cc b/streaming/src/test/mock_actor.cc
--- a/streaming/src/test/mock_actor.cc
+++ b/streaming/src/test/mock_actor.cc
@@ -496,8 +496,8 @@ class StreamingWorker {
         "",                  // driver_name
         "",                  // stdout_file
         "",                  // stderr_file
-        std::bind(&StreamingWorker::ExecuteTask, this, _1, _2, _3, _4, _5, _6,
-                  _7),  // task_execution_callback
+        std::bind(&StreamingWorker::ExecuteTask, this, _1, _2, _3, _4, _5, _6, _7,
+                  _8),  // task_execution_callback
         nullptr,        // check_signals
         nullptr,        // gc_collect
         nullptr,        // spill_objects
@@ -521,7 +521,8 @@ class StreamingWorker {
   }
 
  private:
-  Status ExecuteTask(TaskType task_type, const RayFunction &ray_function,
+  Status ExecuteTask(TaskType task_type, const std::string task_name,
+                     const RayFunction &ray_function,
                      const std::unordered_map<std::string, double> &required_resources,
                      const std::vector<std::shared_ptr<RayObject>> &args,
                      const std::vector<ObjectID> &arg_reference_ids,
diff --git a/streaming/src/test/queue_tests_base.h b/streaming/src/test/queue_tests_base.h
--- a/streaming/src/test/queue_tests_base.h
+++ b/streaming/src/test/queue_tests_base.h
@@ -87,7 +87,7 @@ class StreamingQueueTestBase : public ::testing::TestWithParam<uint64_t> {
     args.emplace_back(new TaskArgByValue(std::make_shared<RayObject>(
         msg.ToBytes(), nullptr, std::vector<ObjectID>(), true)));
     std::unordered_map<std::string, double> resources;
-    TaskOptions options{0, resources};
+    TaskOptions options{"", 0, resources};
     std::vector<ObjectID> return_ids;
     RayFunction func{ray::Language::PYTHON,
                      ray::FunctionDescriptorBuilder::BuildPython("", "", "init", "")};
@@ -103,7 +103,7 @@ class StreamingQueueTestBase : public ::testing::TestWithParam<uint64_t> {
     args.emplace_back(new TaskArgByValue(
         std::make_shared<RayObject>(buffer, nullptr, std::vector<ObjectID>(), true)));
     std::unordered_map<std::string, double> resources;
-    TaskOptions options{0, resources};
+    TaskOptions options{"", 0, resources};
     std::vector<ObjectID> return_ids;
     RayFunction func{ray::Language::PYTHON, ray::FunctionDescriptorBuilder::BuildPython(
                                                 "", test, "execute_test", "")};
@@ -119,7 +119,7 @@ class StreamingQueueTestBase : public ::testing::TestWithParam<uint64_t> {
     args.emplace_back(new TaskArgByValue(
         std::make_shared<RayObject>(buffer, nullptr, std::vector<ObjectID>(), true)));
     std::unordered_map<std::string, double> resources;
-    TaskOptions options{1, resources};
+    TaskOptions options{"", 1, resources};
     std::vector<ObjectID> return_ids;
     RayFunction func{ray::Language::PYTHON, ray::FunctionDescriptorBuilder::BuildPython(
                                                 "", "", "check_current_test_status", "")};