Skip to content

Commit 2b76a1e

Browse files
authored
FaaS positioning & supporting user-defined methods to handle more HTTP methods (#2111)
1 parent 07fce2a commit 2b76a1e

File tree

234 files changed

+4014
-3321
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

234 files changed

+4014
-3321
lines changed

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,6 @@ If you are only modifying the CLI, `make cli-watch` will build the CLI and re-bu
219219

220220
If you are only modifying the operator, `make operator-local` will build and start the operator locally, and build/restart it when files are changed.
221221

222-
If you are modifying code in the API images (i.e. any of the Python serving code), `make images-dev` may build more images than you need during testing. For example, if you are only testing using the `python-predictor-cpu` image, you can run `./dev/registry.sh update-single python-predictor-cpu`.
222+
If you are modifying code in the API images (i.e. any of the Python serving code), `make images-dev` may build more images than you need during testing. For example, if you are only testing using the `python-handler-cpu` image, you can run `./dev/registry.sh update-single python-handler-cpu`.
223223

224224
See `Makefile` for additional dev commands.

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ images-api-skip-push:
144144
images-manager-skip-push:
145145
@./dev/registry.sh update-single manager --skip-push
146146
images-iris:
147-
@./dev/registry.sh update-single python-predictor-cpu
147+
@./dev/registry.sh update-single python-handler-cpu
148148

149149
registry-create:
150150
@./dev/registry.sh create

build/build-image.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ fi
2929

3030
build_args=""
3131

32-
if [ "${image}" == "python-predictor-gpu" ]; then
32+
if [ "${image}" == "python-handler-gpu" ]; then
3333
cuda=("10.0" "10.1" "10.1" "10.2" "10.2" "11.0" "11.1")
3434
cudnn=("7" "7" "8" "7" "8" "8" "8")
3535
for i in ${!cudnn[@]}; do

build/images.sh

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@
2020
set -euo pipefail
2121

2222
api_images=(
23-
"python-predictor-cpu"
24-
"python-predictor-gpu"
25-
"tensorflow-predictor"
26-
"python-predictor-inf"
23+
"python-handler-cpu"
24+
"python-handler-gpu"
25+
"tensorflow-handler"
26+
"python-handler-inf"
2727
)
2828

2929
dev_images=(

build/push-image.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ image=$2
2424

2525
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
2626

27-
if [ "$image" == "python-predictor-gpu" ]; then
27+
if [ "$image" == "python-handler-gpu" ]; then
2828
cuda=("10.0" "10.1" "10.1" "10.2" "10.2" "11.0" "11.1")
2929
cudnn=("7" "7" "8" "7" "8" "8" "8")
3030
for i in ${!cudnn[@]}; do

cli/cmd/errors.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -286,13 +286,13 @@ func ErrorAPINotFoundInConfig(apiName string) error {
286286
})
287287
}
288288

289-
func ErrorNotSupportedForKindAndType(kind userconfig.Kind, predictorType userconfig.PredictorType) error {
289+
func ErrorNotSupportedForKindAndType(kind userconfig.Kind, handlerType userconfig.HandlerType) error {
290290
return errors.WithStack(&errors.Error{
291291
Kind: ErrNotSupportedForKindAndType,
292-
Message: fmt.Sprintf("this command is still in beta and currently only supports %s with type %s", userconfig.RealtimeAPIKind.String(), userconfig.PythonPredictorType.String()),
292+
Message: fmt.Sprintf("this command is still in beta and currently only supports %s with type %s", userconfig.RealtimeAPIKind.String(), userconfig.PythonHandlerType.String()),
293293
Metadata: map[string]interface{}{
294-
"apiKind": kind.String(),
295-
"predictorType": predictorType.String(),
294+
"apiKind": kind.String(),
295+
"handlerType": handlerType.String(),
296296
},
297297
})
298298
}

cli/cmd/lib_async_apis.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import (
2525
"github.com/cortexlabs/cortex/pkg/lib/table"
2626
libtime "github.com/cortexlabs/cortex/pkg/lib/time"
2727
"github.com/cortexlabs/cortex/pkg/operator/schema"
28-
"github.com/cortexlabs/cortex/pkg/types/userconfig"
2928
)
3029

3130
const (
@@ -47,10 +46,6 @@ func asyncAPITable(asyncAPI schema.APIResponse, env cliconfig.Environment) (stri
4746

4847
out += "\n" + console.Bold("endpoint: ") + asyncAPI.Endpoint + "\n"
4948

50-
if !(asyncAPI.Spec.Predictor.Type == userconfig.PythonPredictorType && asyncAPI.Spec.Predictor.MultiModelReloading == nil) {
51-
out += "\n" + describeModelInput(asyncAPI.Status, asyncAPI.Spec.Predictor, asyncAPI.Endpoint)
52-
}
53-
5449
out += "\n" + apiHistoryTable(asyncAPI.APIVersions)
5550

5651
if !_flagVerbose {

cli/cmd/lib_realtime_apis.go

Lines changed: 18 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ import (
2929
"github.com/cortexlabs/cortex/pkg/consts"
3030
"github.com/cortexlabs/cortex/pkg/lib/console"
3131
"github.com/cortexlabs/cortex/pkg/lib/errors"
32-
"github.com/cortexlabs/cortex/pkg/lib/json"
3332
s "github.com/cortexlabs/cortex/pkg/lib/strings"
3433
"github.com/cortexlabs/cortex/pkg/lib/table"
3534
libtime "github.com/cortexlabs/cortex/pkg/lib/time"
@@ -52,15 +51,18 @@ func realtimeAPITable(realtimeAPI schema.APIResponse, env cliconfig.Environment)
5251
out += "\n" + console.Bold("metrics dashboard: ") + *realtimeAPI.DashboardURL + "\n"
5352
}
5453

55-
if realtimeAPI.Spec.Predictor.IsGRPC() {
54+
if realtimeAPI.Spec.Handler.IsGRPC() {
5655
out += "\n" + console.Bold("insecure endpoint: ") + fmt.Sprintf("%s:%d", realtimeAPI.Endpoint, realtimeAPI.GRPCPorts["insecure"])
5756
out += "\n" + console.Bold("secure endpoint: ") + fmt.Sprintf("%s:%d", realtimeAPI.Endpoint, realtimeAPI.GRPCPorts["secure"]) + "\n"
5857
} else {
5958
out += "\n" + console.Bold("endpoint: ") + realtimeAPI.Endpoint + "\n"
6059
}
6160

62-
if !(realtimeAPI.Spec.Predictor.Type == userconfig.PythonPredictorType && realtimeAPI.Spec.Predictor.MultiModelReloading == nil) && realtimeAPI.Spec.Predictor.ProtobufPath == nil {
63-
out += "\n" + describeModelInput(realtimeAPI.Status, realtimeAPI.Spec.Predictor, realtimeAPI.Endpoint)
61+
if !(realtimeAPI.Spec.Handler.Type == userconfig.PythonHandlerType && realtimeAPI.Spec.Handler.MultiModelReloading == nil) && realtimeAPI.Spec.Handler.ProtobufPath == nil {
62+
decribedModels := describeModelInput(realtimeAPI.Status, realtimeAPI.RealtimeModelMetadata.TFModelSummary, realtimeAPI.RealtimeModelMetadata.PythonModelSummary)
63+
if decribedModels != "" {
64+
out += "\n" + decribedModels
65+
}
6466
}
6567

6668
out += "\n" + apiHistoryTable(realtimeAPI.APIVersions)
@@ -158,39 +160,28 @@ func code5XXStr(metrics *metrics.Metrics) string {
158160
return s.Int(metrics.NetworkStats.Code5XX)
159161
}
160162

161-
func describeModelInput(status *status.Status, predictor *userconfig.Predictor, apiEndpoint string) string {
163+
func describeModelInput(status *status.Status, apiTFLiveReloadingSummary *schema.TFLiveReloadingSummary, apiModelSummary *schema.PythonModelSummary) string {
162164
if status.Updated.Ready+status.Stale.Ready == 0 {
163165
return "the models' metadata schema will be available when the api is live\n"
164166
}
165167

166-
cachingEnabled := predictor.Models != nil && predictor.Models.CacheSize != nil && predictor.Models.DiskCacheSize != nil
167-
if predictor.Type == userconfig.TensorFlowPredictorType && !cachingEnabled {
168-
apiTFLiveReloadingSummary, err := getAPITFLiveReloadingSummary(apiEndpoint)
169-
if err != nil {
170-
if strings.Contains(errors.Message(err), "context deadline exceeded") {
171-
return "error retrieving the models' metadata schema: unable to connect to the API, you either do not have access or the API is too busy" + "\n"
172-
}
173-
return "error retrieving the models' metadata schema: " + errors.Message(err) + "\n"
174-
}
168+
if apiTFLiveReloadingSummary != nil {
175169
t, err := parseAPITFLiveReloadingSummary(apiTFLiveReloadingSummary)
176170
if err != nil {
177-
return "error retrieving the model's input schema: " + errors.Message(err) + "\n"
171+
return "error parsing the model's input schema: " + errors.Message(err) + "\n"
178172
}
179173
return t
180174
}
181175

182-
apiModelSummary, err := getAPIModelSummary(apiEndpoint)
183-
if err != nil {
184-
if strings.Contains(errors.Message(err), "context deadline exceeded") {
185-
return "error retrieving the models' metadata schema: unable to connect to the API, you either do not have access or the API is too busy" + "\n"
176+
if apiModelSummary != nil {
177+
t, err := parseAPIModelSummary(apiModelSummary)
178+
if err != nil {
179+
return "error parsing the models' metadata schema: " + errors.Message(err) + "\n"
186180
}
187-
return "error retrieving the models' metadata schema: " + errors.Message(err) + "\n"
188-
}
189-
t, err := parseAPIModelSummary(apiModelSummary)
190-
if err != nil {
191-
return "error retrieving the models' metadata schema: " + errors.Message(err) + "\n"
181+
return t
192182
}
193-
return t
183+
184+
return ""
194185
}
195186

196187
func getModelFromModelID(modelID string) (modelName string, modelVersion int64, err error) {
@@ -229,45 +220,7 @@ func makeRequest(request *http.Request) (http.Header, []byte, error) {
229220
return response.Header, bodyBytes, nil
230221
}
231222

232-
func getAPIModelSummary(apiEndpoint string) (*schema.APIModelSummary, error) {
233-
req, err := http.NewRequest("GET", apiEndpoint, nil)
234-
if err != nil {
235-
return nil, errors.Wrap(err, "unable to request api summary")
236-
}
237-
req.Header.Set("Content-Type", "application/json")
238-
_, response, err := makeRequest(req)
239-
if err != nil {
240-
return nil, err
241-
}
242-
243-
var apiModelSummary schema.APIModelSummary
244-
err = json.DecodeWithNumber(response, &apiModelSummary)
245-
if err != nil {
246-
return nil, errors.Wrap(err, "unable to parse api summary response")
247-
}
248-
return &apiModelSummary, nil
249-
}
250-
251-
func getAPITFLiveReloadingSummary(apiEndpoint string) (*schema.APITFLiveReloadingSummary, error) {
252-
req, err := http.NewRequest("GET", apiEndpoint, nil)
253-
if err != nil {
254-
return nil, errors.Wrap(err, "unable to request api summary")
255-
}
256-
req.Header.Set("Content-Type", "application/json")
257-
_, response, err := makeRequest(req)
258-
if err != nil {
259-
return nil, err
260-
}
261-
262-
var apiTFLiveReloadingSummary schema.APITFLiveReloadingSummary
263-
err = json.DecodeWithNumber(response, &apiTFLiveReloadingSummary)
264-
if err != nil {
265-
return nil, errors.Wrap(err, "unable to parse api summary response")
266-
}
267-
return &apiTFLiveReloadingSummary, nil
268-
}
269-
270-
func parseAPIModelSummary(summary *schema.APIModelSummary) (string, error) {
223+
func parseAPIModelSummary(summary *schema.PythonModelSummary) (string, error) {
271224
rows := make([][]interface{}, 0)
272225

273226
for modelName, modelMetadata := range summary.ModelMetadata {
@@ -324,7 +277,7 @@ func parseAPIModelSummary(summary *schema.APIModelSummary) (string, error) {
324277
return t.MustFormat(), nil
325278
}
326279

327-
func parseAPITFLiveReloadingSummary(summary *schema.APITFLiveReloadingSummary) (string, error) {
280+
func parseAPITFLiveReloadingSummary(summary *schema.TFLiveReloadingSummary) (string, error) {
328281
latestVersions := make(map[string]int64)
329282

330283
numRows := 0

cli/cmd/prepare_debug.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,10 @@ var _prepareDebugCmd = &cobra.Command{
8484
}
8585

8686
if apiToPrepare.Kind != userconfig.RealtimeAPIKind {
87-
exit.Error(ErrorNotSupportedForKindAndType(apiToPrepare.Kind, userconfig.UnknownPredictorType))
87+
exit.Error(ErrorNotSupportedForKindAndType(apiToPrepare.Kind, userconfig.UnknownHandlerType))
8888
}
89-
if apiToPrepare.Predictor.Type != userconfig.PythonPredictorType {
90-
exit.Error(ErrorNotSupportedForKindAndType(apiToPrepare.Kind, apiToPrepare.Predictor.Type))
89+
if apiToPrepare.Handler.Type != userconfig.PythonHandlerType {
90+
exit.Error(ErrorNotSupportedForKindAndType(apiToPrepare.Kind, apiToPrepare.Handler.Type))
9191
}
9292

9393
apiSpec := spec.API{
@@ -107,6 +107,6 @@ docker run -p 9000:8888 \
107107
-e "CORTEX_VERSION=%s" \
108108
-e "CORTEX_API_SPEC=/mnt/project/%s" \
109109
-v %s:/mnt/project \
110-
%s`, consts.CortexVersion, debugFileName, path.Clean(projectRoot), apiToPrepare.Predictor.Image))
110+
%s`, consts.CortexVersion, debugFileName, path.Clean(projectRoot), apiToPrepare.Handler.Image))
111111
},
112112
}

dev/load/cortex.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
- name: load
1616
kind: RealtimeAPI
17-
predictor:
17+
handler:
1818
type: python
1919
path: predictor.py
2020
log_level: debug

dev/load/predictor.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from cortex_internal.lib.log import logger as cortex_logger
1818

1919

20-
class PythonPredictor:
20+
class Handler:
2121
def __init__(self, config):
2222
num_success = 0
2323
num_fail = 0
@@ -58,5 +58,5 @@ def __init__(self, config):
5858
extra={"finished": True, "num_success": num_success, "num_fail": num_fail},
5959
)
6060

61-
def predict(self, payload):
61+
def handle_post(self, payload):
6262
return "ok"

dev/registry.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ function build_and_push() {
138138
set -euo pipefail # necessary since this is called in a new shell by parallel
139139

140140
tag=$CORTEX_VERSION
141-
if [ "${image}" == "python-predictor-gpu" ]; then
141+
if [ "${image}" == "python-handler-gpu" ]; then
142142
tag="${CORTEX_VERSION}-cuda10.2-cudnn8"
143143
fi
144144

dev/versions.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ Note: it's ok if example training notebooks aren't upgraded, as long as the expo
191191
1. Check if there are any updates
192192
to [Dockerfile.neuron-rtd](https://github.com/aws/aws-neuron-sdk/blob/master/docs/neuron-container-tools/docker-example/Dockerfile.neuron-rtd)
193193
which should be brought in to `images/neuron-rtd/Dockerfile`
194-
1. Set the version of `aws-neuron-tools` and `aws-neuron-runtime` in `images/python-predictor-inf/Dockerfile`
194+
1. Set the version of `aws-neuron-tools` and `aws-neuron-runtime` in `images/python-handler-inf/Dockerfile`
195195
and `images/tensorflow-serving-inf/Dockerfile`
196196
1. Run `docker run --rm -it ubuntu:18.04`
197197
1. Run the first `RUN` command used in `images/tensorflow-serving-inf/Dockerfile`, having omitted the version specified
@@ -214,15 +214,15 @@ Note: it's ok if example training notebooks aren't upgraded, as long as the expo
214214

215215
## S6-overlay supervisor
216216

217-
1. Locate the `s6-overlay` installation in `images/python-predictor-*/Dockerfile` and `images/tensorflow-predictor/Dockerfile`.
217+
1. Locate the `s6-overlay` installation in `images/python-handler-*/Dockerfile` and `images/tensorflow-handler/Dockerfile`.
218218
1. Update the version in each serving image with the newer one in https://github.com/just-containers/s6-overlay.
219219

220220
## Nginx
221221

222222
1. Run a base image of ubuntu that matches the version tag used for the serving images. The running command
223223
is `docker run -it --rm <base-image>`
224224
1. Run `apt update && apt-cache policy nginx`. Notice the latest minor version of nginx (e.g. `1.14`)
225-
1. Locate the `nginx` package in `images/python-predictor-*/Dockerfile` and `images/tensorflow-predictor/Dockerfile`.
225+
1. Locate the `nginx` package in `images/python-handler-*/Dockerfile` and `images/tensorflow-handler/Dockerfile`.
226226
1. Update the version for all `nginx` appearances using the minor version from step 2 and add an asterisk at the end to
227227
denote any version (e.g. `1.14.*`)
228228

docs/clients/python.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,18 +81,18 @@ Delete an environment configured on this machine.
8181
<!-- CORTEX_VERSION_MINOR -->
8282

8383
```python
84-
| create_api(api_spec: dict, predictor=None, task=None, requirements=[], conda_packages=[], project_dir: Optional[str] = None, force: bool = True, wait: bool = False) -> list
84+
| create_api(api_spec: dict, handler=None, task=None, requirements=[], conda_packages=[], project_dir: Optional[str] = None, force: bool = True, wait: bool = False) -> list
8585
```
8686

8787
Deploy an API.
8888

8989
**Arguments**:
9090

9191
- `api_spec` - A dictionary defining a single Cortex API. See https://docs.cortex.dev/v/master/ for schema.
92-
- `predictor` - A Cortex Predictor class implementation. Not required for TaskAPI/TrafficSplitter kinds.
92+
- `handler` - A Cortex handler class implementation. Not required for TaskAPI/TrafficSplitter kinds.
9393
- `task` - A callable class/function implementation. Not required for RealtimeAPI/BatchAPI/TrafficSplitter kinds.
94-
- `requirements` - A list of PyPI dependencies that will be installed before the predictor class implementation is invoked.
95-
- `conda_packages` - A list of Conda dependencies that will be installed before the predictor class implementation is invoked.
94+
- `requirements` - A list of PyPI dependencies that will be installed before the handler class implementation is invoked.
95+
- `conda_packages` - A list of Conda dependencies that will be installed before the handler class implementation is invoked.
9696
- `project_dir` - Path to a python project.
9797
- `force` - Override any in-progress api updates.
9898
- `wait` - Streams logs until the APIs are ready.

docs/clusters/observability/logging.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ enable you to add custom metadata to the logs.
7272

7373
See the structured logging docs for each API kind:
7474

75-
- [RealtimeAPI](../../workloads/realtime/predictors.md#structured-logging)
76-
- [AsyncAPI](../../workloads/async/predictors.md#structured-logging)
77-
- [BatchAPI](../../workloads/batch/predictors.md#structured-logging)
75+
- [RealtimeAPI](../../workloads/realtime/handler.md#structured-logging)
76+
- [AsyncAPI](../../workloads/async/handler.md#structured-logging)
77+
- [BatchAPI](../../workloads/batch/handler.md#structured-logging)
7878
- [TaskAPI](../../workloads/task/definitions.md#structured-logging)

docs/clusters/observability/metrics.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ You can use any of these metrics to set up your own dashboards.
7272

7373
## Custom user metrics
7474

75-
It is possible to export your own custom metrics by using the `MetricsClient` class in your predictor code. This allows
75+
It is possible to export your own custom metrics by using the `MetricsClient` class in your handler code. This allows
7676
you to create a custom metrics from your deployed API that can be later be used on your own custom dashboards.
7777

7878
Code examples on how to use custom metrics for each API kind can be found here:

docs/summary.md

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,32 +30,34 @@
3030

3131
* Realtime APIs
3232
* [Example](workloads/realtime/example.md)
33-
* [Predictor](workloads/realtime/predictors.md)
34-
* [Configuration](workloads/realtime/configuration.md)
33+
* [Handler](workloads/realtime/handler.md)
3534
* [Models](workloads/realtime/models.md)
35+
* Multi-model
36+
* [Example](workloads/realtime/multi-model/example.md)
37+
* [Configuration](workloads/realtime/multi-model/configuration.md)
38+
* [Caching](workloads/realtime/multi-model/caching.md)
39+
* [Configuration](workloads/realtime/configuration.md)
3640
* [Parallelism](workloads/realtime/parallelism.md)
3741
* [Server-side batching](workloads/realtime/server-side-batching.md)
3842
* [Autoscaling](workloads/realtime/autoscaling.md)
3943
* [Statuses](workloads/realtime/statuses.md)
4044
* [Metrics](workloads/realtime/metrics.md)
41-
* Multi-model
42-
* [Example](workloads/realtime/multi-model/example.md)
43-
* [Configuration](workloads/realtime/multi-model/configuration.md)
44-
* [Caching](workloads/realtime/multi-model/caching.md)
4545
* Traffic Splitter
4646
* [Example](workloads/realtime/traffic-splitter/example.md)
4747
* [Configuration](workloads/realtime/traffic-splitter/configuration.md)
4848
* [Troubleshooting](workloads/realtime/troubleshooting.md)
4949
* [Async APIs](workloads/async/async-apis.md)
5050
* [Example](workloads/async/example.md)
51-
* [Predictor](workloads/async/predictors.md)
51+
* [Handler](workloads/async/handler.md)
52+
* [Models](workloads/async/models.md)
5253
* [Configuration](workloads/async/configuration.md)
5354
* [Statuses](workloads/async/statuses.md)
5455
* [Webhooks](workloads/async/webhooks.md)
5556
* [Metrics](workloads/async/metrics.md)
5657
* Batch APIs
5758
* [Example](workloads/batch/example.md)
58-
* [Predictor](workloads/batch/predictors.md)
59+
* [Handler](workloads/batch/handler.md)
60+
* [Models](workloads/batch/models.md)
5961
* [Configuration](workloads/batch/configuration.md)
6062
* [Jobs](workloads/batch/jobs.md)
6163
* [Statuses](workloads/batch/statuses.md)

docs/workloads/async/autoscaling.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,6 @@ image and for the api to initialize (via its `__init__()` method).
103103
If you want the autoscaler to react as quickly as possible, set `upscale_stabilization_period` and `window` to their
104104
minimum values (0s and 10s respectively).
105105

106-
If it takes a long time to initialize your API replica (i.e. install dependencies and run your predictor's `__init__()`
106+
If it takes a long time to initialize your API replica (i.e. install dependencies and run your handler's `__init__()`
107107
function), consider building your own API image to use instead of the default image. With this approach, you can
108108
pre-download/build/install any custom dependencies and bake them into the image.

0 commit comments

Comments
 (0)