skypilot-nightly 1.0.0.dev20250427__py3-none-any.whl → 1.0.0.dev20250429__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. sky/__init__.py +2 -2
  2. sky/adaptors/nebius.py +28 -40
  3. sky/backends/backend_utils.py +19 -2
  4. sky/backends/cloud_vm_ray_backend.py +33 -8
  5. sky/backends/local_docker_backend.py +1 -2
  6. sky/cli.py +91 -38
  7. sky/client/cli.py +91 -38
  8. sky/client/sdk.py +3 -2
  9. sky/clouds/aws.py +12 -6
  10. sky/clouds/azure.py +3 -0
  11. sky/clouds/cloud.py +8 -2
  12. sky/clouds/cudo.py +2 -0
  13. sky/clouds/do.py +3 -0
  14. sky/clouds/fluidstack.py +3 -0
  15. sky/clouds/gcp.py +7 -0
  16. sky/clouds/ibm.py +2 -0
  17. sky/clouds/kubernetes.py +42 -19
  18. sky/clouds/lambda_cloud.py +1 -0
  19. sky/clouds/nebius.py +18 -10
  20. sky/clouds/oci.py +6 -3
  21. sky/clouds/paperspace.py +2 -0
  22. sky/clouds/runpod.py +2 -0
  23. sky/clouds/scp.py +2 -0
  24. sky/clouds/service_catalog/constants.py +1 -1
  25. sky/clouds/service_catalog/kubernetes_catalog.py +7 -7
  26. sky/clouds/vast.py +2 -0
  27. sky/clouds/vsphere.py +2 -0
  28. sky/core.py +58 -29
  29. sky/dashboard/out/404.html +1 -1
  30. sky/dashboard/out/clusters/[cluster]/[job].html +1 -1
  31. sky/dashboard/out/clusters/[cluster].html +1 -1
  32. sky/dashboard/out/clusters.html +1 -1
  33. sky/dashboard/out/favicon.ico +0 -0
  34. sky/dashboard/out/index.html +1 -1
  35. sky/dashboard/out/jobs/[job].html +1 -1
  36. sky/dashboard/out/jobs.html +1 -1
  37. sky/exceptions.py +6 -0
  38. sky/execution.py +19 -4
  39. sky/global_user_state.py +1 -0
  40. sky/optimizer.py +35 -11
  41. sky/provision/common.py +2 -5
  42. sky/provision/docker_utils.py +22 -16
  43. sky/provision/instance_setup.py +1 -1
  44. sky/provision/kubernetes/instance.py +276 -93
  45. sky/provision/kubernetes/network.py +1 -1
  46. sky/provision/kubernetes/utils.py +36 -24
  47. sky/provision/provisioner.py +6 -0
  48. sky/serve/replica_managers.py +51 -5
  49. sky/serve/serve_state.py +41 -0
  50. sky/serve/service.py +108 -63
  51. sky/server/common.py +6 -3
  52. sky/server/config.py +184 -0
  53. sky/server/requests/executor.py +17 -156
  54. sky/server/server.py +4 -4
  55. sky/setup_files/dependencies.py +0 -1
  56. sky/skylet/constants.py +7 -0
  57. sky/skypilot_config.py +27 -6
  58. sky/task.py +1 -1
  59. sky/templates/kubernetes-ray.yml.j2 +145 -15
  60. sky/templates/nebius-ray.yml.j2 +63 -0
  61. sky/utils/command_runner.py +17 -3
  62. sky/utils/command_runner.pyi +2 -0
  63. sky/utils/controller_utils.py +24 -0
  64. sky/utils/kubernetes/rsync_helper.sh +20 -4
  65. sky/utils/schemas.py +13 -0
  66. {skypilot_nightly-1.0.0.dev20250427.dist-info → skypilot_nightly-1.0.0.dev20250429.dist-info}/METADATA +2 -2
  67. {skypilot_nightly-1.0.0.dev20250427.dist-info → skypilot_nightly-1.0.0.dev20250429.dist-info}/RECORD +73 -72
  68. {skypilot_nightly-1.0.0.dev20250427.dist-info → skypilot_nightly-1.0.0.dev20250429.dist-info}/WHEEL +1 -1
  69. /sky/dashboard/out/_next/static/{kTfCjujxwqIQ4b7YvP7Uq → BMtJJ079_cyYmtW2-7nVS}/_buildManifest.js +0 -0
  70. /sky/dashboard/out/_next/static/{kTfCjujxwqIQ4b7YvP7Uq → BMtJJ079_cyYmtW2-7nVS}/_ssgManifest.js +0 -0
  71. {skypilot_nightly-1.0.0.dev20250427.dist-info → skypilot_nightly-1.0.0.dev20250429.dist-info}/entry_points.txt +0 -0
  72. {skypilot_nightly-1.0.0.dev20250427.dist-info → skypilot_nightly-1.0.0.dev20250429.dist-info}/licenses/LICENSE +0 -0
  73. {skypilot_nightly-1.0.0.dev20250427.dist-info → skypilot_nightly-1.0.0.dev20250429.dist-info}/top_level.txt +0 -0
sky/server/config.py ADDED
@@ -0,0 +1,184 @@
1
+ """SkyPilot API Server configuration."""
2
+
3
+ import dataclasses
4
+ import enum
5
+
6
+ from sky import sky_logging
7
+ from sky.server import constants as server_constants
8
+ from sky.utils import common_utils
9
+
10
+ # Constants based on profiling the peak memory usage while serving various
11
+ # sky commands. These estimation are highly related to usage patterns
12
+ # (clouds enabled, type of requests, etc. see `tests/load_tests` for details.),
13
+ # the profiling covers major clouds and common usage patterns. For user has
14
+ # deviated usage pattern, they can override the default estimation by
15
+ # environment variables.
16
+ # NOTE(dev): update these constants for each release according to the load
17
+ # test results.
18
+ # TODO(aylei): maintaining these constants is error-prone, we may need to
19
+ # automatically tune parallelism at runtime according to system usage stats
20
+ # in the future.
21
+ _LONG_WORKER_MEM_GB = 0.4
22
+ _SHORT_WORKER_MEM_GB = 0.25
23
+ # To control the number of long workers.
24
+ _CPU_MULTIPLIER_FOR_LONG_WORKERS = 2
25
+ # Limit the number of long workers of local API server, since local server is
26
+ # typically:
27
+ # 1. launched automatically in an environment with high resource contention
28
+ # (e.g. Laptop)
29
+ # 2. used by a single user
30
+ _MAX_LONG_WORKERS_LOCAL = 4
31
+ # Percentage of memory for long requests
32
+ # from the memory reserved for SkyPilot.
33
+ # This is to reserve some memory for short requests.
34
+ _MAX_MEM_PERCENT_FOR_BLOCKING = 0.6
35
+ # Minimal number of long workers to ensure responsiveness.
36
+ _MIN_LONG_WORKERS = 1
37
+ # Minimal number of short workers, there is a daemon task running on short
38
+ # workers so at least 2 workers are needed to ensure responsiveness.
39
+ _MIN_SHORT_WORKERS = 2
40
+
41
+ # Default number of burstable workers for local API server. A heuristic number
42
+ # that is large enough for most local cases.
43
+ # TODO(aylei): the number of burstable workers should be auto-tuned based on the
44
+ # system usage stats.
45
+ _BURSTABLE_WORKERS_FOR_LOCAL = 1024
46
+
47
+ logger = sky_logging.init_logger(__name__)
48
+
49
+
50
+ class QueueBackend(enum.Enum):
51
+ # Local queue backend serves queues in each process locally, which has
52
+ # lower resource usage but the consumer must be in the same process, i.e.
53
+ # this only works in single-process mode.
54
+ LOCAL = 'local'
55
+ # Multi-process queue backend starts a dedicated process for serving queues.
56
+ MULTIPROCESSING = 'multiprocessing'
57
+ # TODO(zhwu): we can add redis backend in the future.
58
+
59
+
60
+ @dataclasses.dataclass
61
+ class WorkerConfig:
62
+ garanteed_parallelism: int
63
+ burstable_parallelism: int
64
+
65
+
66
+ @dataclasses.dataclass
67
+ class ServerConfig:
68
+ num_server_workers: int
69
+ long_worker_config: WorkerConfig
70
+ short_worker_config: WorkerConfig
71
+ queue_backend: QueueBackend
72
+
73
+
74
+ def compute_server_config(deploy: bool) -> ServerConfig:
75
+ """Compute the server config based on environment.
76
+
77
+ We have different assumptions for the resources in different deployment
78
+ modes, which leads to different worker setups:
79
+
80
+ - Deployment mode (deploy=True), we assume the resources are dedicated to
81
+ the API server and the resources will be tuned for serious use cases, so:
82
+ - Use multiprocessing queue backend and dedicated workers processes to
83
+ avoid GIL contention.
84
+ - Parallelism (number of executor processes) is fixed and executor
85
+ processes have same lifecycle with the server, which ensures
86
+ best-effort cache reusing and stable resources consumption.
87
+ - Reject to start in low resource environments, to avoid flaky
88
+ deployments.
89
+ - Local mode (deploy=False), we assume the server is running in a shared
90
+ environment (e.g. laptop) and users typically do not pay attention to
91
+ the resource setup of the server. Moreover, existing users may expect
92
+ some consistent behaviors with old versions, i.e. before API server was
93
+ introduced, so:
94
+ - The max number of long-running executor processes are limited, to avoid
95
+ high memory consumption when the server is idle.
96
+ - Allow burstable workers to handle requests when all long-running
97
+ workers are busy, which mimics the behavior of local sky CLI before
98
+ API server was introduced.
99
+ - Works in low resources environments, and further reduce the memory
100
+ consumption in low resource environments.
101
+
102
+ Note that there is still significant overhead for SDK users when migrate to
103
+ local API server. Since the users are free to run sky operations in Threads
104
+ when using SDK but all client operations will occupy at least one worker
105
+ process after API server was introduced.
106
+ """
107
+ cpu_count = common_utils.get_cpu_count()
108
+ mem_size_gb = common_utils.get_mem_size_gb()
109
+ max_parallel_for_long = _max_long_worker_parallism(cpu_count,
110
+ mem_size_gb,
111
+ local=not deploy)
112
+ max_parallel_for_short = _max_short_worker_parallism(
113
+ mem_size_gb, max_parallel_for_long)
114
+ queue_backend = QueueBackend.MULTIPROCESSING
115
+ burstable_parallel_for_long = 0
116
+ burstable_parallel_for_short = 0
117
+ num_server_workers = cpu_count
118
+ if not deploy:
119
+ # For local mode, use local queue backend since we only run 1 uvicorn
120
+ # worker in local mode and no multiprocessing is needed.
121
+ num_server_workers = 1
122
+ queue_backend = QueueBackend.LOCAL
123
+ # Enable burstable workers for local API server.
124
+ burstable_parallel_for_long = _BURSTABLE_WORKERS_FOR_LOCAL
125
+ burstable_parallel_for_short = _BURSTABLE_WORKERS_FOR_LOCAL
126
+ # Runs in low resource mode if the available memory is less than
127
+ # server_constants.MIN_AVAIL_MEM_GB.
128
+ if not deploy and mem_size_gb < server_constants.MIN_AVAIL_MEM_GB:
129
+ # Permanent worker process may have significant memory consumption
130
+ # (~350MB per worker) after running commands like `sky check`, so we
131
+ # don't start any permanent workers in low resource local mode. This
132
+ # mimics the behavior of local sky CLI before API server was
133
+ # introduced, where the CLI will start new process everytime and
134
+ # never reject to start due to resource constraints.
135
+ # Note that the refresh daemon will still occupy one worker
136
+ # permanently because it never exits.
137
+ max_parallel_for_long = 0
138
+ max_parallel_for_short = 0
139
+ logger.warning(
140
+ 'SkyPilot API server will run in low resource mode because '
141
+ 'the available memory is less than '
142
+ f'{server_constants.MIN_AVAIL_MEM_GB}GB.')
143
+ logger.info(
144
+ f'SkyPilot API server will start {num_server_workers} server processes '
145
+ f'with {max_parallel_for_long} background workers for long requests '
146
+ f'and will allow at max {max_parallel_for_short} short requests in '
147
+ f'parallel.')
148
+ return ServerConfig(
149
+ num_server_workers=num_server_workers,
150
+ queue_backend=queue_backend,
151
+ long_worker_config=WorkerConfig(
152
+ garanteed_parallelism=max_parallel_for_long,
153
+ burstable_parallelism=burstable_parallel_for_long),
154
+ short_worker_config=WorkerConfig(
155
+ garanteed_parallelism=max_parallel_for_short,
156
+ burstable_parallelism=burstable_parallel_for_short),
157
+ )
158
+
159
+
160
+ def _max_long_worker_parallism(cpu_count: int,
161
+ mem_size_gb: float,
162
+ local=False) -> int:
163
+ """Max parallelism for long workers."""
164
+ # Reserve min available memory to avoid OOM.
165
+ available_mem = max(0, mem_size_gb - server_constants.MIN_AVAIL_MEM_GB)
166
+ cpu_based_max_parallel = cpu_count * _CPU_MULTIPLIER_FOR_LONG_WORKERS
167
+ mem_based_max_parallel = int(available_mem * _MAX_MEM_PERCENT_FOR_BLOCKING /
168
+ _LONG_WORKER_MEM_GB)
169
+ n = max(_MIN_LONG_WORKERS,
170
+ min(cpu_based_max_parallel, mem_based_max_parallel))
171
+ if local:
172
+ return min(n, _MAX_LONG_WORKERS_LOCAL)
173
+ return n
174
+
175
+
176
+ def _max_short_worker_parallism(mem_size_gb: float,
177
+ long_worker_parallism: int) -> int:
178
+ """Max parallelism for short workers."""
179
+ # Reserve memory for long workers and min available memory.
180
+ reserved_mem = server_constants.MIN_AVAIL_MEM_GB + (long_worker_parallism *
181
+ _LONG_WORKER_MEM_GB)
182
+ available_mem = max(0, mem_size_gb - reserved_mem)
183
+ n = max(_MIN_SHORT_WORKERS, int(available_mem / _SHORT_WORKER_MEM_GB))
184
+ return n
@@ -19,7 +19,6 @@ The number of the workers is determined by the system resources.
19
19
  See the [README.md](../README.md) for detailed architecture of the executor.
20
20
  """
21
21
  import contextlib
22
- import enum
23
22
  import multiprocessing
24
23
  import os
25
24
  import queue as queue_lib
@@ -37,6 +36,7 @@ from sky import models
37
36
  from sky import sky_logging
38
37
  from sky import skypilot_config
39
38
  from sky.server import common as server_common
39
+ from sky.server import config as server_config
40
40
  from sky.server import constants as server_constants
41
41
  from sky.server.requests import payloads
42
42
  from sky.server.requests import preconditions
@@ -70,53 +70,6 @@ logger = sky_logging.init_logger(__name__)
70
70
  # platforms, including macOS.
71
71
  multiprocessing.set_start_method('spawn', force=True)
72
72
 
73
- # Constants based on profiling the peak memory usage while serving various
74
- # sky commands. These estimation are highly related to usage patterns
75
- # (clouds enabled, type of requests, etc. see `tests/load_tests` for details.),
76
- # the profiling covers major clouds and common usage patterns. For user has
77
- # deviated usage pattern, they can override the default estimation by
78
- # environment variables.
79
- # NOTE(dev): update these constants for each release according to the load
80
- # test results.
81
- # TODO(aylei): maintaining these constants is error-prone, we may need to
82
- # automatically tune parallelism at runtime according to system usage stats
83
- # in the future.
84
- _LONG_WORKER_MEM_GB = 0.4
85
- _SHORT_WORKER_MEM_GB = 0.25
86
- # To control the number of long workers.
87
- _CPU_MULTIPLIER_FOR_LONG_WORKERS = 2
88
- # Limit the number of long workers of local API server, since local server is
89
- # typically:
90
- # 1. launched automatically in an environment with high resource contention
91
- # (e.g. Laptop)
92
- # 2. used by a single user
93
- _MAX_LONG_WORKERS_LOCAL = 4
94
- # Percentage of memory for long requests
95
- # from the memory reserved for SkyPilot.
96
- # This is to reserve some memory for short requests.
97
- _MAX_MEM_PERCENT_FOR_BLOCKING = 0.6
98
- # Minimal number of long workers to ensure responsiveness.
99
- _MIN_LONG_WORKERS = 1
100
- # Minimal number of short workers, there is a daemon task running on short
101
- # workers so at least 2 workers are needed to ensure responsiveness.
102
- _MIN_SHORT_WORKERS = 2
103
-
104
- # Default number of burstable workers for local API server. A heuristic number
105
- # that is large enough for most local cases.
106
- # TODO(aylei): the number of burstable workers should be auto-tuned based on the
107
- # system usage stats.
108
- _BURSTABLE_WORKERS_FOR_LOCAL = 1024
109
-
110
-
111
- class QueueBackend(enum.Enum):
112
- # Local queue backend serves queues in each process locally, which has
113
- # lower resource usage but the consumer must be in the same process, i.e.
114
- # this only works in single-process mode.
115
- LOCAL = 'local'
116
- # Multi-process queue backend starts a dedicated process for serving queues.
117
- MULTIPROCESSING = 'multiprocessing'
118
- # TODO(zhwu): we can add redis backend in the future.
119
-
120
73
 
121
74
  class RequestQueue:
122
75
  """The queue for the requests, either redis or multiprocessing.
@@ -126,12 +79,12 @@ class RequestQueue:
126
79
 
127
80
  def __init__(self,
128
81
  schedule_type: api_requests.ScheduleType,
129
- backend: Optional[QueueBackend] = None) -> None:
82
+ backend: Optional[server_config.QueueBackend] = None) -> None:
130
83
  self.name = schedule_type.value
131
84
  self.backend = backend
132
- if backend == QueueBackend.MULTIPROCESSING:
85
+ if backend == server_config.QueueBackend.MULTIPROCESSING:
133
86
  self.queue = mp_queue.get_queue(self.name)
134
- elif backend == QueueBackend.LOCAL:
87
+ elif backend == server_config.QueueBackend.LOCAL:
135
88
  self.queue = local_queue.get_queue(self.name)
136
89
  else:
137
90
  raise RuntimeError(f'Invalid queue backend: {backend}')
@@ -162,7 +115,7 @@ class RequestQueue:
162
115
  return self.queue.qsize()
163
116
 
164
117
 
165
- queue_backend = QueueBackend.MULTIPROCESSING
118
+ queue_backend = server_config.QueueBackend.MULTIPROCESSING
166
119
 
167
120
 
168
121
  def executor_initializer(proc_group: str):
@@ -186,13 +139,11 @@ class RequestWorker:
186
139
  # if there are available CPU/memory resources.
187
140
  burstable_parallelism: int = 0
188
141
 
189
- def __init__(self,
190
- schedule_type: api_requests.ScheduleType,
191
- garanteed_parallelism: int,
192
- burstable_parallelism: int = 0) -> None:
142
+ def __init__(self, schedule_type: api_requests.ScheduleType,
143
+ config: server_config.WorkerConfig) -> None:
193
144
  self.schedule_type = schedule_type
194
- self.garanteed_parallelism = garanteed_parallelism
195
- self.burstable_parallelism = burstable_parallelism
145
+ self.garanteed_parallelism = config.garanteed_parallelism
146
+ self.burstable_parallelism = config.burstable_parallelism
196
147
 
197
148
  def __str__(self) -> str:
198
149
  return f'Worker(schedule_type={self.schedule_type.value})'
@@ -455,80 +406,17 @@ def schedule_request(
455
406
  enqueue()
456
407
 
457
408
 
458
- def start(deploy: bool) -> List[multiprocessing.Process]:
409
+ def start(config: server_config.ServerConfig) -> List[multiprocessing.Process]:
459
410
  """Start the request workers.
460
411
 
461
412
  Request workers run in background, schedule the requests and delegate the
462
- request execution to executor processes. We have different assumptions for
463
- the resources in different deployment modes, which leads to different
464
- worker setups:
465
-
466
- - Deployment mode (deploy=True), we assume the resources are dedicated to
467
- the API server and the resources will be tuned for serious use cases, so:
468
- - Use multiprocessing queue backend and dedicated workers processes to
469
- avoid GIL contention.
470
- - Parallelism (number of executor processes) is fixed and executor
471
- processes have same lifecycle with the server, which ensures
472
- best-effort cache reusing and stable resources consumption.
473
- - Reject to start in low resource environments, to avoid flaky
474
- deployments.
475
- - Local mode (deploy=False), we assume the server is running in a shared
476
- environment (e.g. laptop) and users typically do not pay attention to
477
- the resource setup of the server. Moreover, existing users may expect
478
- some consistent behaviors with old versions, i.e. before API server was
479
- introduced, so:
480
- - The max number of long-running executor processes are limited, to avoid
481
- high memory consumption when the server is idle.
482
- - Allow burstable workers to handle requests when all long-running
483
- workers are busy, which mimics the behavior of local sky CLI before
484
- API server was introduced.
485
- - Works in low resources environments, and further reduce the memory
486
- consumption in low resource environments.
487
-
488
- Note that there is still significant overhead for SDK users when migrate to
489
- local API server. Since the users are free to run sky operations in Threads
490
- when using SDK but all client operations will occupy at least one worker
491
- process after API server was introduced.
413
+ request execution to executor processes.
492
414
  """
493
- # Determine the job capacity of the workers based on the system resources.
494
- cpu_count = common_utils.get_cpu_count()
495
- mem_size_gb = common_utils.get_mem_size_gb()
496
- mem_size_gb = max(0, mem_size_gb - server_constants.MIN_AVAIL_MEM_GB)
497
- # Runs in low resource mode if the available memory is less than
498
- # server_constants.MIN_AVAIL_MEM_GB.
499
- max_parallel_for_long = _max_long_worker_parallism(cpu_count,
500
- mem_size_gb,
501
- local=not deploy)
502
- max_parallel_for_short = _max_short_worker_parallism(
503
- mem_size_gb, max_parallel_for_long)
504
- if mem_size_gb < server_constants.MIN_AVAIL_MEM_GB:
505
- # Permanent worker process may have significant memory consumption
506
- # (~350MB per worker) after running commands like `sky check`, so we
507
- # don't start any permanent workers in low resource local mode. This
508
- # mimics the behavior of local sky CLI before API server was
509
- # introduced, where the CLI will start new process everytime and
510
- # never reject to start due to resource constraints.
511
- # Note that the refresh daemon will still occupy one worker
512
- # permanently because it never exits.
513
- max_parallel_for_long = 0
514
- max_parallel_for_short = 0
515
- logger.warning(
516
- 'SkyPilot API server will run in low resource mode because '
517
- 'the available memory is less than '
518
- f'{server_constants.MIN_AVAIL_MEM_GB}GB.')
519
- else:
520
- logger.info(
521
- f'SkyPilot API server will start {max_parallel_for_long} workers '
522
- f'for long requests and will allow at max '
523
- f'{max_parallel_for_short} short requests in parallel.')
524
- if not deploy:
525
- # For local mode, use local queue backend since we only run 1 uvicorn
526
- # worker in local mode.
527
- global queue_backend
528
- queue_backend = QueueBackend.LOCAL
415
+ global queue_backend
416
+ queue_backend = config.queue_backend
529
417
  sub_procs = []
530
418
  # Setup the queues.
531
- if queue_backend == QueueBackend.MULTIPROCESSING:
419
+ if queue_backend == server_config.QueueBackend.MULTIPROCESSING:
532
420
  logger.info('Creating shared request queues')
533
421
  queue_names = [
534
422
  schedule_type.value for schedule_type in api_requests.ScheduleType
@@ -547,7 +435,7 @@ def start(deploy: bool) -> List[multiprocessing.Process]:
547
435
  mp_queue.wait_for_queues_to_be_ready(queue_names,
548
436
  queue_server,
549
437
  port=port)
550
- elif queue_backend == QueueBackend.LOCAL:
438
+ elif queue_backend == server_config.QueueBackend.LOCAL:
551
439
  # No setup is needed for local queue backend.
552
440
  pass
553
441
  else:
@@ -563,40 +451,13 @@ def start(deploy: bool) -> List[multiprocessing.Process]:
563
451
  thread = threading.Thread(target=worker.run, daemon=True)
564
452
  thread.start()
565
453
 
566
- burstable_parallelism = _BURSTABLE_WORKERS_FOR_LOCAL if not deploy else 0
567
454
  # Start a worker for long requests.
568
455
  long_worker = RequestWorker(schedule_type=api_requests.ScheduleType.LONG,
569
- garanteed_parallelism=max_parallel_for_long,
570
- burstable_parallelism=burstable_parallelism)
456
+ config=config.long_worker_config)
571
457
  run_worker_in_background(long_worker)
572
458
 
573
459
  # Start a worker for short requests.
574
460
  short_worker = RequestWorker(schedule_type=api_requests.ScheduleType.SHORT,
575
- garanteed_parallelism=max_parallel_for_short,
576
- burstable_parallelism=burstable_parallelism)
461
+ config=config.short_worker_config)
577
462
  run_worker_in_background(short_worker)
578
463
  return sub_procs
579
-
580
-
581
- @annotations.lru_cache(scope='global', maxsize=1)
582
- def _max_long_worker_parallism(cpu_count: int,
583
- mem_size_gb: float,
584
- local=False) -> int:
585
- """Max parallelism for long workers."""
586
- cpu_based_max_parallel = cpu_count * _CPU_MULTIPLIER_FOR_LONG_WORKERS
587
- mem_based_max_parallel = int(mem_size_gb * _MAX_MEM_PERCENT_FOR_BLOCKING /
588
- _LONG_WORKER_MEM_GB)
589
- n = max(_MIN_LONG_WORKERS,
590
- min(cpu_based_max_parallel, mem_based_max_parallel))
591
- if local:
592
- return min(n, _MAX_LONG_WORKERS_LOCAL)
593
- return n
594
-
595
-
596
- @annotations.lru_cache(scope='global', maxsize=1)
597
- def _max_short_worker_parallism(mem_size_gb: float,
598
- long_worker_parallism: int) -> int:
599
- """Max parallelism for short workers."""
600
- available_mem = mem_size_gb - (long_worker_parallism * _LONG_WORKER_MEM_GB)
601
- n = max(_MIN_SHORT_WORKERS, int(available_mem / _SHORT_WORKER_MEM_GB))
602
- return n
sky/server/server.py CHANGED
@@ -35,6 +35,7 @@ from sky.jobs.server import server as jobs_rest
35
35
  from sky.provision.kubernetes import utils as kubernetes_utils
36
36
  from sky.serve.server import server as serve_rest
37
37
  from sky.server import common
38
+ from sky.server import config as server_config
38
39
  from sky.server import constants as server_constants
39
40
  from sky.server import stream_utils
40
41
  from sky.server.requests import executor
@@ -1166,13 +1167,12 @@ if __name__ == '__main__':
1166
1167
  # that it is shown only when the API server is started.
1167
1168
  usage_lib.maybe_show_privacy_policy()
1168
1169
 
1169
- num_workers = 1
1170
- if cmd_args.deploy:
1171
- num_workers = common_utils.get_cpu_count()
1170
+ config = server_config.compute_server_config(cmd_args.deploy)
1171
+ num_workers = config.num_server_workers
1172
1172
 
1173
1173
  sub_procs = []
1174
1174
  try:
1175
- sub_procs = executor.start(deploy=cmd_args.deploy)
1175
+ sub_procs = executor.start(config)
1176
1176
  logger.info(f'Starting SkyPilot API server, workers={num_workers}')
1177
1177
  # We don't support reload for now, since it may cause leakage of request
1178
1178
  # workers or interrupt running requests.
@@ -53,7 +53,6 @@ install_requires = [
53
53
  'aiofiles',
54
54
  'httpx',
55
55
  'setproctitle',
56
- 'omegaconf>=2.4.0dev3,<2.5',
57
56
  ]
58
57
 
59
58
  local_ray = [
sky/skylet/constants.py CHANGED
@@ -368,6 +368,13 @@ ROLE_ASSIGNMENT_FAILURE_ERROR_MSG = (
368
368
  'Failed to assign Storage Blob Data Owner role to the '
369
369
  'storage account {storage_account_name}.')
370
370
 
371
+ # Constants for path in K8S pod to store persistent setup and run scripts
372
+ # so that we can run them again after the pod restarts.
373
+ # Path within user home. For HA controller, assumes home directory is
374
+ # persistent through PVC. See kubernetes-ray.yml.j2.
375
+ PERSISTENT_SETUP_SCRIPT_PATH = '~/.sky/.controller_recovery_setup_commands.sh'
376
+ PERSISTENT_RUN_SCRIPT_DIR = '~/.sky/.controller_recovery_task_run'
377
+
371
378
  # The placeholder for the local skypilot config path in file mounts for
372
379
  # controllers.
373
380
  LOCAL_SKYPILOT_CONFIG_PATH_PLACEHOLDER = 'skypilot:local_skypilot_config_path'
sky/skypilot_config.py CHANGED
@@ -56,8 +56,6 @@ import threading
56
56
  import typing
57
57
  from typing import Any, Dict, Iterator, List, Optional, Tuple
58
58
 
59
- from omegaconf import OmegaConf
60
-
61
59
  from sky import exceptions
62
60
  from sky import sky_logging
63
61
  from sky.adaptors import common as adaptors_common
@@ -321,6 +319,31 @@ def _parse_config_file(config_path: str) -> config_utils.Config:
321
319
  return config
322
320
 
323
321
 
322
+ def _parse_dotlist(dotlist: List[str]) -> config_utils.Config:
323
+ """Parse a comma-separated list of key-value pairs into a dictionary.
324
+
325
+ Args:
326
+ dotlist: A comma-separated list of key-value pairs.
327
+
328
+ Returns:
329
+ A config_utils.Config object with the parsed key-value pairs.
330
+ """
331
+ config: config_utils.Config = config_utils.Config()
332
+ for arg in dotlist:
333
+ try:
334
+ key, value = arg.split('=', 1)
335
+ except ValueError as e:
336
+ raise ValueError(f'Invalid config override: {arg}. '
337
+ 'Please use the format: key=value') from e
338
+ if len(key) == 0 or len(value) == 0:
339
+ raise ValueError(f'Invalid config override: {arg}. '
340
+ 'Please use the format: key=value')
341
+ value = yaml.safe_load(value)
342
+ nested_keys = tuple(key.split('.'))
343
+ config.set_nested(nested_keys, value)
344
+ return config
345
+
346
+
324
347
  def _reload_config_from_internal_file(internal_config_path: str) -> None:
325
348
  global _dict, _loaded_config_path
326
349
  # Reset the global variables, to avoid using stale values.
@@ -483,11 +506,9 @@ def _compose_cli_config(cli_config: Optional[List[str]]) -> config_utils.Config:
483
506
  'Cannot use multiple --config flags with a config file.')
484
507
  config_source = maybe_config_path
485
508
  # cli_config is a path to a config file
486
- parsed_config = OmegaConf.to_object(
487
- OmegaConf.load(maybe_config_path))
509
+ parsed_config = _parse_config_file(maybe_config_path)
488
510
  else: # cli_config is a comma-separated list of key-value pairs
489
- parsed_config = OmegaConf.to_object(
490
- OmegaConf.from_dotlist(cli_config))
511
+ parsed_config = _parse_dotlist(cli_config)
491
512
  _validate_config(parsed_config, config_source)
492
513
  except ValueError as e:
493
514
  raise ValueError(f'Invalid config override: {cli_config}. '
sky/task.py CHANGED
@@ -306,7 +306,7 @@ class Task:
306
306
  self.service_name: Optional[str] = None
307
307
 
308
308
  # Filled in by the optimizer. If None, this Task is not planned.
309
- self.best_resources = None
309
+ self.best_resources: Optional[sky.Resources] = None
310
310
 
311
311
  # For internal use only.
312
312
  self.file_mounts_mapping = file_mounts_mapping