[Yandex Cloud documentation](../../index.md) > [Tutorials](../index.md) > [Serverless technologies](index.md) > Serverless-based workflows and automation > Deploying a fault-tolerant architecture with preemptible VMs

# Deploying a fault-tolerant architecture with preemptible VMs

# Deploying a fault-tolerant architecture with preemptible VMs


In this tutorial, you will create a scheduled [Yandex Cloud Functions](../../functions/index.md) [function](../../functions/concepts/function.md) in [Node.js](../../functions/lang/nodejs/index.md) that will start a [preemptible Yandex Compute Cloud VM](../../compute/concepts/preemptible-vm.md) if it was stopped.

The architecture we use here is suitable for [VMs](../../compute/concepts/vm.md) with non-critical loads. It allows you to reduce expenses by using preemptible VMs and, in case a VM goes down, ensures that idle time is no more than 60 seconds.

To deploy a fault-tolerant architecture with a preemptible VM:
1. [Set up your environment](#prepare).
1. [Prepare a ZIP archive with the function code](#zip-archive).
1. [Create a function](#func-create).
1. [Create a trigger](#trigger-create).
1. [Test the function](#test).

If you no longer need the resources you created, [delete them](#clear-out).

## Getting started {#before-you-begin}

Sign up for Yandex Cloud and create a [billing account](../../billing/concepts/billing-account.md):
1. Navigate to the [management console](https://console.yandex.cloud) and log in to Yandex Cloud or create a new account.
1. On the **[Yandex Cloud Billing](https://center.yandex.cloud/billing/accounts)** page, make sure you have a billing account linked and it has the `ACTIVE` or `TRIAL_ACTIVE` [status](../../billing/concepts/billing-account-statuses.md). If you do not have a billing account, [create one](../../billing/quickstart/index.md) and [link](../../billing/operations/pin-cloud.md) a cloud to it.

If you have an active billing account, you can create or select a [folder](../../resource-manager/concepts/resources-hierarchy.md#folder) for your infrastructure on the [cloud page](https://console.yandex.cloud/cloud).

[Learn more about clouds and folders here](../../resource-manager/concepts/resources-hierarchy.md).

### Required paid resources {#paid-resources}

The infrastructure support costs include:
* Fee for VM computing resources (see [Compute Cloud pricing](../../compute/pricing.md#prices-instance-resources)).
* Fee for VM [disks](../../compute/concepts/disk.md) (see [Compute Cloud pricing](../../compute/pricing.md#prices-storage)).
* Fee for a static or dynamic [public IP address](../../vpc/concepts/address.md#public-addresses) (see [Yandex Virtual Private Cloud pricing](../../vpc/pricing.md#prices-public-ip)).
* Fee for the number of function calls, computing resources allocated for the function, and outgoing traffic (see [Cloud Functions pricing](../../functions/pricing.md)).
* Fee for logging operations and data storage in a [log group](../../logging/concepts/log-group.md) (see [Yandex Cloud Logging pricing](../../logging/pricing.md)) when using [Cloud Logging](../../logging/index.md).

## Set up your environment {#prepare}

1. [Create](../../iam/operations/sa/create.md) a [service account](../../iam/concepts/users/service-accounts.md) for calling the function and [assign](../../iam/operations/sa/assign-role-for-sa.md) the `functions.functionInvoker` and `compute.operator` [roles](../../iam/concepts/access-control/roles.md) to it.
1. [Create](../../compute/operations/vm-create/create-preemptible-vm.md#create-preemptible) a preemptible VM.

## Create a ZIP archive with the function code {#zip-archive}

1. Save the following code to a file named `index.js`:

   ```javascript
   import { Session } from '@yandex-cloud/nodejs-sdk';
   import { instanceService, instance } from '@yandex-cloud/nodejs-sdk/compute-v1';

   const FOLDER_ID = process.env.FOLDER_ID;
   const INSTANCE_ID = process.env.INSTANCE_ID;

   export const handler = async function (event, context) {
     const session = new Session({ iamToken: context.token.access_token });
     const instanceClient = session.client(instanceService.InstanceServiceClient);

     const list = await instanceClient.list(instanceService.ListInstancesRequest.fromPartial({
       folderId: FOLDER_ID,
     }));

     const state = await instanceClient.get(instanceService.GetInstanceRequest.fromPartial({
       instanceId: INSTANCE_ID,
     }));

     var status = state.status;

     if (status == 4) {
       await instanceClient.start(instanceService.StartInstanceRequest.fromPartial({
         instanceId: INSTANCE_ID,
       }));
     }

     return {
       statusCode: 200,
       body: { status },
     };
   };
   ```

1. Save this code to a file named `package.json`:

   ```json
   {
     "name": "my-awesome-package",
     "version": "1.0.0",
     "type": "module",
     "dependencies": {
       "@yandex-cloud/nodejs-sdk": "latest"
     }
   }
   ```

1. Add the `index.js` and `package.json` files into the `function-js.zip` archive.

## Create a function {#func-create}

{% list tabs group=instructions %}

- Management console {#console}

  1. In the [management console](https://console.yandex.cloud), select the folder where you want to create a function.
  1. Navigate to **Cloud Functions**.
  1. Create a function:
     1. Click **Create function**.
     1. In the window that opens, enter `function-restart-vms` as the function name.
     1. Click **Create**.
  1. Create a [function version](../../functions/concepts/function.md#version):
     1. Select `nodejs22` as the runtime, disable **Add files with code examples**, and click **Continue**.
     1. In the **Code source** field, select `ZIP archive`.
     1. In the **File** field, click **Attach file** and select the `function-js.zip` archive you created earlier.
     1. Specify the entry point: `index.handler`.
     1. Under **Parameters**, specify:
        * **Timeout**: `3`.
        * **Memory**: `128 MB`.
        * **Service account**: Select the previously created service account with permissions to call the function.
        * **Environment variables**:
          * `FOLDER_ID`: [ID of the folder](../../resource-manager/operations/folder/get-id.md) where you want to start the stopped VM.
          * `INSTANCE_ID`: [ID of the VM](../../compute/operations/vm-info/get-info.md#outside-instance) you want to start at interruption.
        * If you want to avoid logging and paying for Cloud Logging, disable logging by selecting `Not specified` in the **Logging** field under **Destination**.
     1. Click **Save changes**.

- CLI {#cli}

  1. Create a function named `function-restart-vms`:

     ```bash
     yc serverless function create --name function-restart-vms
     ```

     Result:

     ```text
     id: d4ebrmenrr7l********
     folder_id: b1g9d2k0itu4********
     created_at: "2023-10-28T17:26:58.200799757Z"
     name: function-restart-vms
     http_invoke_url: https://functions.yandexcloud.net/d4ebrmenrr7l********
     status: ACTIVE
     ```

  1. Create a [version](../../functions/concepts/function.md#version) of the `function-restart-vms` function:

     ```bash
     yc serverless function version create \
       --function-name function-restart-vms \
       --memory=128m \
       --execution-timeout=3s \
       --runtime=nodejs22 \
       --entrypoint=index.handler \
       --service-account-id=<service_account_ID> \
       --environment FOLDER_ID=<folder_ID>,INSTANCE_ID=<VM_ID> \
       --source-path=./function-js.zip \
       --no-logging
     ```

     Where:
     * `--function-name`: Name of the function whose version you are creating.
     * `--memory`: Amount of RAM.
     * `--execution-timeout`: Maximum function runtime before timeout.
     * `--runtime`: Runtime.
     * `--entrypoint`: Entry point.
     * `--service-account-id`: [ID](../../iam/operations/sa/get-id.md) of the service account with permissions to invoke the function.
     * `--environment`: Environment variables:
       * `FOLDER_ID`: [ID of the folder](../../resource-manager/operations/folder/get-id.md) where you want to start the stopped VM.
       * `INSTANCE_ID`: [ID of the VM](../../compute/operations/vm-info/get-info.md#outside-instance) you want to start at interruption.
     * `--source-path`: Path to the `function-js.zip` archive you created earlier.
     * Optionally, set the `--no-logging` flag to avoid logging and paying for Cloud Logging.

     Result:

     ```text
     done (16s)
     id: d4etv5f4sjet********
     function_id: d4ebrmenrr7l********
     ...
     log_options:
       disabled: true
       folder_id: b1g9d2k0itu4********
     ```

- Terraform {#tf}

  If you do not have Terraform yet, [install it and configure Yandex Cloud](../infrastructure-management/terraform-quickstart.md#install-terraform).
  1. In the configuration file, describe the `function-restart-vms` parameters and [versions](../../functions/concepts/function.md#version):

     ```hcl
     resource "yandex_function" "function-restart-vms" {
       name               = "function-restart-vms"
       user_hash          = "first function"
       runtime            = "nodejs22"
       entrypoint         = "index.handler"
       memory             = "128"
       execution_timeout  = "3"
       service_account_id = "<service_account_ID>"
       folder_id = "<folder_ID>"
       environment = {
         FOLDER_ID = "<folder_ID>"
         INSTANCE_ID = "<VM_ID>"
       }
       content {
         zip_filename = "./function-js.zip"
       }
     }
     ```

     Where:
     * `name`: Function name.
     * `user_hash`: Any string to identify the function version.
     * `runtime`: Function [runtime](../../functions/concepts/runtime/index.md).
     * `entrypoint`: Entry point.
     * `memory`: Amount of memory allocated for the function, in MB.
     * `execution_timeout`: Function execution timeout.
     * `service_account_id`: [ID](../../iam/operations/sa/get-id.md) of the service account with permissions to invoke the function.
     * `folder_id`: [ID of the folder](../../resource-manager/operations/folder/get-id.md) where you are creating the function.
     * `environment`: Environment variables:
       * `FOLDER_ID`: ID of the folder where you want to start the stopped VM.
       * `INSTANCE_ID`: [ID of the VM](../../compute/operations/vm-info/get-info.md#outside-instance) you want to start at interruption.
     * `zip_filename`: Path to the `function-js.zip` archive you created earlier.

     For more information about `yandex_function` properties, see [this provider guide](../../terraform/resources/function.md).
  1. Make sure the configuration files are correct.
     1. In the terminal, navigate to the directory where you created your configuration file.
     1. Run a check using this command:

        ```bash
        terraform plan
        ```

     If the configuration is correct, the terminal will display a list of the resources and their settings. Otherwise, Terraform will show any detected errors.
  1. Deploy the cloud resources.
     1. If the configuration is correct, run this command:

        ```bash
        terraform apply
        ```

     1. Confirm creating the function by typing `yes` in the terminal and pressing **Enter**.

        This will create a function named `function-restart-vms` in the specified folder. You can check the new resources and their settings using the [management console](https://console.yandex.cloud) or this [CLI](../../cli/quickstart.md) command:

        ```bash
        yc serverless function get function-restart-vms
        ```

        Result:

        ```text
        id: d4ees84gsdsd********
        folder_id: b1g9d2k0itu4********
        created_at: "2023-08-09T10:11:40.740Z"
        name: function-restart-vms
        log_group_id: ckgjitlio5aj********
        http_invoke_url: https://functions.yandexcloud.net/d4ees84gsdsd********
        status: ACTIVE
        ```

- API {#api}

  To create a function, use the [create](../../functions/functions/api-ref/Function/create.md) REST API method for the [Function](../../functions/functions/api-ref/Function/index.md) resource or the [FunctionService/Create](../../functions/functions/api-ref/grpc/Function/create.md) gRPC API call.

  To create a function version, use the [createVersion](../../functions/functions/api-ref/Function/createVersion.md) REST API method for the [Function](../../functions/functions/api-ref/Function/index.md) resource or the [FunctionService/CreateVersion](../../functions/functions/api-ref/grpc/Function/createVersion.md) gRPC API call.

{% endlist %}

## Create a trigger {#trigger-create}

{% note info %}

The trigger is initiated within five minutes after it is created.

{% endnote %}

{% list tabs group=instructions %}

- Management console {#console}

  1. In the [management console](https://console.yandex.cloud), select the folder where you want to create a [trigger](../../functions/concepts/trigger/index.md).
  1. Navigate to **Cloud Functions**.
  1. In the left-hand panel, select ![image](../../_assets/console-icons/gear-play.svg) **Triggers**.
  1. Click **Create trigger**.
  1. Under **Basic settings**:
     * Enter the trigger name: `timer`.
     * In the **Type** field, select `Timer`.
     * In the **Launched resource** field, select `Function`.
  1. Under **Timer settings**, enter `* * ? * * *` or select `Every minute`.
  1. Under **Function settings**, select `function-restart-vms` and specify the following:
     * [**Function version tag**](../../functions/concepts/function.md#tag): `$latest`.
     * Service account you created earlier with permissions to call the function.
  1. Click **Create trigger**.

- CLI {#cli}

  To create a [trigger](../../functions/concepts/trigger/index.md) that calls a function, run this command:

  ```bash
  yc serverless trigger create timer \
    --name timer \
    --cron-expression '* * ? * * *' \
    --invoke-function-name function-restart-vms \
    --invoke-function-service-account-id <service_account_ID>
  ```

  Where:
  * `--name`: Trigger name.
  * `--cron-expression`: Function call schedule specified as a [cron expression](../../functions/concepts/trigger/timer.md#cron-expression).
  * `--invoke-function-name`: Name of the function to call.
  * `--invoke-function-service-account-id`: ID of the service account with permissions to invoke the function.

  Result:

  ```text
  id: a1sv54ekvknb********
  folder_id: b1g9d2k0itu4********
  created_at: "2023-08-08T19:46:22.860681482Z"
  ...
        function_tag: $latest
        service_account_id: ajeh2dukocg3********
  status: ACTIVE
  ```

- Terraform {#tf}

  To create a [trigger](../../functions/concepts/trigger/index.md) that launches a function:
  1. In the configuration file, describe the `timer` trigger parameters:

     ```hcl
     resource "yandex_function_trigger" "timer" {
       name        = "timer"
       timer {
         cron_expression = "* * ? * * *"
       }
       function {
         id = "<function_ID>"
         service_account_id = "<service_account_ID>"
       }
     }
     ```

     Where:
     * `name`: Trigger name.
     * `cron_expression`: Function call schedule specified as a [cron expression](../../functions/concepts/trigger/timer.md#cron-expression).
     * `id`: ID of the function for the trigger to call.
     * `service_account_id`: ID of the service account with permissions to invoke the function.

     For more information about resource parameters in Terraform, see [this provider guide](../../terraform/resources/function_trigger.md).
  1. Make sure the configuration files are correct.
     1. In the terminal, navigate to the directory where you created your configuration file.
     1. Run a check using this command:

        ```bash
        terraform plan
        ```

     If the configuration is correct, the terminal will display a list of the resources and their settings. Otherwise, Terraform will show any detected errors.
  1. Deploy the cloud resources.
     1. If the configuration is correct, run this command:

        ```bash
        terraform apply
        ```

     1. Confirm creating the resources: type `yes` and press **Enter**.

        This will create a trigger named `timer` in the specified folder. You can check the new resources and their settings using the [management console](https://console.yandex.cloud) or this [CLI](../../cli/quickstart.md) command:

        ```bash
        yc serverless trigger get timer
        ```

        Result:

        ```text
        id: a1s4bvdvmod0********
        folder_id: b1g9d2k0itu4********
        created_at: "2023-08-09T10:19:12.356Z"
        ...
              function_id: d4ebrmenrr7l********
              service_account_id: ajeh2dukocg3********
        status: ACTIVE
        ```

- API {#api}

  To create a timer, use the [create](../../functions/triggers/api-ref/Trigger/create.md) REST API method for the [Trigger](../../functions/triggers/api-ref/Trigger/index.md) resource or the [TriggerService/Create](../../functions/triggers/api-ref/grpc/Trigger/create.md) gRPC API call.

{% endlist %}

## Test the function {#test}

{% list tabs group=instructions %}

- Management console {#console}

  1. In the [management console](https://console.yandex.cloud), navigate to the folder where you created your preemptible VM.
  1. Navigate to **Compute Cloud**.
  1. In the left-hand panel, select **Virtual machines**.
  1. Click ![image](../../_assets/console-icons/ellipsis.svg) next to the VM name and select **Stop**.
  1. In the window that opens, click **Stop**. The VM status will change to `Stopped`.
  1. Check the VM status in about one minute or later. The VM status should now be `Running`.

{% endlist %}

## How to delete the resources you created {#clear-out}

To stop paying for the resources you created:
1. [Delete the trigger](../../functions/operations/trigger/trigger-delete.md).
1. [Delete the function](../../functions/operations/function/function-delete.md).
1. [Delete the VM](../../compute/operations/vm-control/vm-delete.md).
1. If you logged data to a log group, [delete it](../../logging/operations/delete-group.md).