4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Salesforce Functionsを試してみる(ローカルでの実行まで)

Last updated at Posted at 2021-09-30

1. やること

  • Salesforce Functionsを触ってみる

2. バージョンや背景など

  • Summer '21 (2021/9/30時点)
  • FunctionsのBeta登録に遅れたため、組織に接続できない
  • FunctionsはWinter '22でGAだけど、リリース直前でまだGAになっていない

3. 試したこと

3.1. Beta登録を試みた

3.2. Salesforce Functions SFDX Pluginのインストールを試みた

% sfdx update
% sfdx plugins:install @salesforce/plugin-functions
  • 実施結果
% sfdx --version
sfdx-cli/7.119.2 darwin-x64 node-v14.17.6
% sfdx plugins
functions 0.2.50
└─ @oclif/plugin-not-found 1.2.4

3.3. Salesforce組織でFunctionsの有効化を試みた

  • https://developer.salesforce.com/docs/platform/functions/guide/devhub-auth.html
  • [設定 > 機能設定 > 関数]のページを表示したが、やはりまだ有効化できない様子
    • クイック検索で「関数」だけでなく「function」でも、該当ページがヒットした
    • [User]では「ユーザ」ページはヒットしなかった
    • 英語でもヒットするようになると少し嬉しいかもしれない

スクリーンショット 2021-09-30 10.19.03.png

3.4. Functionの作成を試みた

% sfdx generate:project -n MyFunctionProject
   create MyFunctionProject/config/project-scratch-def.json
   create MyFunctionProject/README.md
   create MyFunctionProject/sfdx-project.json
   create MyFunctionProject/.husky/pre-commit
   create MyFunctionProject/.vscode/extensions.json
   create MyFunctionProject/.vscode/launch.json
   create MyFunctionProject/.vscode/settings.json
   create MyFunctionProject/force-app/main/default/lwc/.eslintrc.json
   create MyFunctionProject/force-app/main/default/aura/.eslintrc.json
   create MyFunctionProject/scripts/soql/account.soql
   create MyFunctionProject/scripts/apex/hello.apex
   create MyFunctionProject/.eslintignore
   create MyFunctionProject/.forceignore
   create MyFunctionProject/.gitignore
   create MyFunctionProject/.prettierignore
   create MyFunctionProject/.prettierrc
   create MyFunctionProject/jest.config.js
   create MyFunctionProject/package.json
  • Functionを作成する
    • 公式サイトの例ではjavascriptだが、javaを選択してみる
    • 2021/9/30時点で、公式サイトの例のオプション名が古いよう。--nameを使用すると--function-nameを使ってほしいとのメッセージが出た
    • sfdx generate:function --function-name myfunction --language java
% cd MyFunctionProject 
% sfdx generate:function --function-name myfunction --language java
Created java function myfunction in ~~省略~~/MyFunctionProject/functions/myfunction.

Before creating Scratch Orgs for development, please ensure that:
1. Enable Functions in your DevHub org
2. Add Functions to the "features" list in your scratch org definition JSON file, e.g. "features": ["Functions"]

スクラッチ組織を作成する前に実施すべきことが記載されている。
1. Enable Functions in your DevHub orgは、先ほど試みたが、今(2021/9/30)はまだできない

3.3. Functionsをfeaturesに設定して、スクラッチ組織の作成を試みた

  • DevHub組織でFunctionsを有効化できていないので失敗すると思われる
  • config/project-scratch-def.json内のfeaturesにFunctionsを追加
% cat config/project-scratch-def.json 
{
  "orgName": "company",
  "edition": "Developer",
  "features": ["EnableSetPasswordInApi", "Functions"],
  "settings": {
    "lightningExperienceSettings": {
      "enableS1DesktopEnabled": true
    },
    "mobileSettings": {
      "enableS1EncryptedStoragePref2": false
    }
  }
}
  • スクラッチ組織を作成してみる
    • Functionsが有効化していないため、スクラッチ組織の作成に失敗する様子
% sfdx force:org:create -f config/project-scratch-def.json -a scratch -v devhub
ERROR running force:org:create:  Functions は有効な機能値ではありません。

3.4. 作成されたFunctionsのコードを確認してみた

  • SFDXプロジェクトの配下にfunctionsというフォルダが作成される
% ls
README.md		force-app		jest.config.js		scripts
config			functions		package.json		sfdx-project.json
  • functionsフォルダ内に作成したmyFunctionがある
% ls functions 
myfunction
  • 作成されたFunctionはMaven形式の様子
% cd functions/myfunction 
% ls
mvnw		mvnw.cmd	pom.xml		project.toml	src
  • 作成されたpom.xmlは以下のようになっていた
    • Javaバージョンは1.8
    • com.salesforce.functions:sf-fx-sdk-java をdependsしている
    • JUnit4だったりする
  • mvnw clean package でBUILD SUCCESSすることを確認
shigeo.tejima@tejimasgeonoair myfunction % cat pom.xml 
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>myfunction</artifactId>
    <version>1.0-SNAPSHOT</version>

    <name>myfunction</name>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.salesforce.functions</groupId>
            <artifactId>sf-fx-sdk-java</artifactId>
            <version>1.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.30</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-core</artifactId>
            <version>3.6.28</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest</artifactId>
            <version>2.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.spotify</groupId>
            <artifactId>hamcrest-pojo</artifactId>
            <version>1.2.0</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <artifactId>maven-clean-plugin</artifactId>
                    <version>3.1.0</version>
                </plugin>
                <plugin>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.0</version>
                </plugin>
                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.22.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-jar-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-install-plugin</artifactId>
                    <version>2.5.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-deploy-plugin</artifactId>
                    <version>2.8.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-site-plugin</artifactId>
                    <version>3.7.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-project-info-reports-plugin</artifactId>
                    <version>3.0.0</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>
  • 作成されたコードは以下のようになっていた
% cd src/main/java/com/example/
% ls
Account.java		FunctionInput.java	FunctionOutput.java	MyfunctionFunction.java
% cat Account.java 
package com.example;

public class Account {
    private final String id;
    private final String name;

    public Account(String id, String name) {
        this.id = id;
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}
% cat FunctionInput.java 
package com.example;

public class FunctionInput {
}
% cat FunctionOutput.java 
package com.example;

import java.util.List;

public class FunctionOutput {
  private final List<Account> accounts;

  public FunctionOutput(List<Account> accounts) {
    this.accounts = accounts;
  }

  public List<Account> getAccounts() {
    return accounts;
  }
}

% cat MyfunctionFunction.java 
package com.example;

import com.salesforce.functions.jvm.sdk.Context;
import com.salesforce.functions.jvm.sdk.InvocationEvent;
import com.salesforce.functions.jvm.sdk.SalesforceFunction;
import com.salesforce.functions.jvm.sdk.data.Record;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;

/**
 * Describe MyfunctionFunction here.
 */
public class MyfunctionFunction implements SalesforceFunction<FunctionInput, FunctionOutput> {
  private static final Logger LOGGER = LoggerFactory.getLogger(MyfunctionFunction.class);

  @Override
  public FunctionOutput apply(InvocationEvent<FunctionInput> event, Context context)
      throws Exception {

    List<Record> records =
        context.getOrg().get().getDataApi().query("SELECT Id, Name FROM Account").getRecords();

    LOGGER.info("Function successfully queried {} account records!", records.size());

    List<Account> accounts = new ArrayList<>();
    for (Record record : records) {
      String id = record.getStringField("Id").get();
      String name = record.getStringField("Name").get();

      accounts.add(new Account(id, name));
    }

    return new FunctionOutput(accounts);
  }
}
  • 組織から取引先(Account)のId,Nameを検索した結果を返す処理の様子

    • 入力, 出力ともにPOJOで書けるようだ
    • FunctionはSalesforceFunction<T,S>を実装する
  • 作成されたテストコードを確認してみる

% cd src/test/java/com/example 
% ls
FunctionTest.java
% cat FunctionTest.java 
package com.example;

import com.salesforce.functions.jvm.sdk.Context;
import com.salesforce.functions.jvm.sdk.InvocationEvent;
import com.salesforce.functions.jvm.sdk.Org;
import com.salesforce.functions.jvm.sdk.data.Record;
import com.salesforce.functions.jvm.sdk.data.RecordQueryResult;
import org.junit.Test;
import org.mockito.Mockito;

import java.util.Arrays;
import java.util.Optional;

import static com.spotify.hamcrest.pojo.IsPojo.pojo;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItems;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class FunctionTest {

  @Test
  public void test() throws Exception {
    MyfunctionFunction function = new MyfunctionFunction();
    FunctionOutput functionOutput = function.apply(createEventMock(), createContextMock());

    assertThat(
        functionOutput.getAccounts(),
        hasItems(
            pojo(Account.class)
                .withProperty("id", equalTo("5003000000D8cuIQAA"))
                .withProperty("name", equalTo("Account One, inc.")),
            pojo(Account.class)
                .withProperty("id", equalTo("6003000000D8cuIQAA"))
                .withProperty("name", equalTo("Account Two, inc."))));
  }

  private Context createContextMock() {
    Context mockContext = mock(Context.class);

    when(mockContext.getOrg()).then(i1 -> {
      Org mockOrg = mock(Org.class, Mockito.RETURNS_DEEP_STUBS);

      when(mockOrg.getDataApi().query("SELECT Id, Name FROM Account")).then(i2 -> {
        RecordQueryResult mockResult = mock(RecordQueryResult.class);

        Record firstRecord = mock(Record.class);
        when(firstRecord.getStringField("Id")).thenReturn(Optional.of("5003000000D8cuIQAA"));
        when(firstRecord.getStringField("Name")).thenReturn(Optional.of("Account One, inc."));

        Record secondRecord = mock(Record.class);
        when(secondRecord.getStringField("Id")).thenReturn(Optional.of("6003000000D8cuIQAA"));
        when(secondRecord.getStringField("Name")).thenReturn(Optional.of("Account Two, inc."));

        when(mockResult.getRecords()).thenReturn(Arrays.asList(firstRecord, secondRecord));

        return mockResult;
      });

      return Optional.of(mockOrg);
    });

    return mockContext;
  }

  private InvocationEvent<FunctionInput> createEventMock() {
    return mock(InvocationEvent.class);
  }
}
  • 組織に接続が必要な箇所やInvocationEventなどは、モックしてテストできる

3.5. 作成されたFunctionをローカルで動かしてみた

    /*
    List<Record> records =
        context.getOrg().get().getDataApi().query("SELECT Id, Name FROM Account").getRecords();

    LOGGER.info("Function successfully queried {} account records!", records.size());

    List<Account> accounts = new ArrayList<>();
    for (Record record : records) {
      String id = record.getStringField("Id").get();
      String name = record.getStringField("Name").get();

      accounts.add(new Account(id, name));
    }
    */

    // demo code without org
    List<Account> accounts = new ArrayList<>();
    accounts.add(new Account("id-1", "account 1"));
    accounts.add(new Account("id-2", "account 2"));
% sfdx run:function -l http://localhost:8080 -p '{}'
 ›   Warning: No -o connected org or defaultusername found, context will be partially initialized
Using defaultusername undefined login credential to initialize context
POST http://localhost:8080... 200
{
  "accounts": [
    {
      "id": "id-1",
      "name": "account 1"
    },
    {
      "id": "id-2",
      "name": "account 2"
    }
  ]
}
  • 期待通りのレスポンスが返ってきた
  • -oオプションで指定するか、defaultusernameを設定するとその組織が使用されそうである
  • 以下のようにhelpを表示すると、-oオプションの説明にそのような記載がある
% sfdx help run:function
Send a cloudevent to a function.

USAGE
  $ sfdx run:function

OPTIONS
  -H, --headers=headers              Set headers.
  -l, --function-url=function-url    Url of the function to run.
  -o, --connected-org=connected-org  Username or alias for the target org; overrides default target org.
  -p, --payload=payload              Set the payload of the cloudevent. also accepts @file.txt format.
  -s, --structured                   Set the cloudevent to be emitted as a structured cloudevent (json).

EXAMPLES
  $ sfdx run:function -l http://localhost:8080 -p '{"id": 12345}'
  $ sfdx run:function -l http://localhost:8080 -p '@file.json'
  $ echo '{"id": 12345}' | sfdx run:function -l http://localhost:8080
  $ sfdx run:function -l http://localhost:8080 -p '{"id": 12345}' --structured

COMMANDS
  run:function:start  Build and run function image locally.

3.6. スクラッチ組織を作成して、ローカルで動かしたFunctionから接続できるか試してみた

  • スクラッチ組織を作成する
    • sfdx force:org:create -f config/project-scratch-def.json -a scratch -v devhub
    • DevHub組織はFunctionsが有効化されていない
    • config/project-scratch-def.jsonのfeaturesにFunctionsは追加していない
  • 取引先(Account)をいくつか作成する
    スクリーンショット 2021-09-30 11.51.50.png
  • 作成されたFunctionのコード MyfunctionFunction.java を元に戻す
  • sfdx run:function:start
  • sfdx run:function -l http://localhost:8080 -p '{}' -o scratch
  • 以下のようにスクラッチ組織の取引先(Account)の情報がレスポンスとして返ってきた
    • defaultusernameにスクラッチ組織が設定されている場合は、-oオプションなしでも同様の結果となった
% sfdx run:function -l http://localhost:8080 -p '{}' -o scratch
Using scratch login credential to initialize context
POST http://localhost:8080... 200
{
  "accounts": [
    {
      "id": "0010l00001M37iwAAB",
      "name": "取引先Bar"
    },
    {
      "id": "0010l00001M35GQAAZ",
      "name": "エンタイトルメントの取引先のサンプル"
    },
    {
      "id": "0010l00001M37imAAB",
      "name": "Account Foo"
    }
  ]
}
  • defaultusernameが未設定、かつ-oオプションでスクラッチ組織を指定しないで、組織に接続しようとすると以下のようなエラーとなった
% sfdx run:function -l http://localhost:8080 -p '{}'           
 ›   Warning: No -o connected org or defaultusername found, context will be partially initialized
Using defaultusername undefined login credential to initialize context
POST http://localhost:8080... 500 Internal Server Error
 ›   Error: Function threw exception: com.salesforce.functions.jvm.sdk.data.error.DataApiException (IOException while executing API 
 ›   request!)
 ›   com.salesforce.functions.jvm.sdk.data.error.DataApiException: IOException while executing API request!
 ›   	at com.salesforce.functions.jvm.runtime.sdk.DataApiImpl.executeRequest(DataApiImpl.java:188)
 ›   	at com.salesforce.functions.jvm.runtime.sdk.DataApiImpl.query(DataApiImpl.java:57)
 ›   	at com.example.MyfunctionFunction.apply(MyfunctionFunction.java:25)
 ›   	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 ›   	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
 ›   	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 ›   	at java.lang.reflect.Method.invoke(Method.java:498)
 ›   	at com.salesforce.functions.jvm.runtime.sfjavafunction.SalesforceFunctionsProjectFunctionsScanner.lambda$scan$0(SalesforceFunct
 ›   ionsProjectFunctionsScanner.java:402)
 ›   	at com.salesforce.functions.jvm.runtime.sfjavafunction.Slf4j1MdcDataInvocationWrapper.invoke(Slf4j1MdcDataInvocationWrapper.jav
 ›   a:81)
 ›   	at com.salesforce.functions.jvm.runtime.sfjavafunction.SalesforceFunction.apply(SalesforceFunction.java:68)
 ›   	at com.salesforce.functions.jvm.runtime.sfjavafunction.SalesforceFunction.apply(SalesforceFunction.java:31)
 ›   	at com.salesforce.functions.jvm.runtime.invocation.undertow.UndertowInvocationInterface$ProjectFunctionHandler.handleRequest(Un
 ›   dertowInvocationInterface.java:160)
 ›   	at io.undertow.server.Connectors.executeRootHandler(Connectors.java:387)
 ›   	at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:852)
 ›   	at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
 ›   	at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2019)
 ›   	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1558)
 ›   	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1449)
 ›   	at org.xnio.XnioWorker$WorkerThreadFactory$1$1.run(XnioWorker.java:1280)
 ›   	at java.lang.Thread.run(Thread.java:748)
 ›   Caused by: org.apache.http.client.ClientProtocolException
 ›   	at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:187)
 ›   	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
 ›   	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)
 ›   	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56)
 ›   	at com.salesforce.functions.jvm.runtime.sdk.restapi.RestApi.execute(RestApi.java:75)
 ›   	at com.salesforce.functions.jvm.runtime.sdk.DataApiImpl.executeRequest(DataApiImpl.java:182)
 ›   	... 19 more
 ›   Caused by: org.apache.http.ProtocolException: Target host is not specified
 ›   	at org.apache.http.impl.conn.DefaultRoutePlanner.determineRoute(DefaultRoutePlanner.java:71)
 ›   	at org.apache.http.impl.client.InternalHttpClient.determineRoute(InternalHttpClient.java:125)
 ›   	at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
 ›   	... 24 more
 ›

3.6. dockerのイメージとコンテナを確認してみた

  • Dockerのイメージ
    • heroku/packheroku/buildpacksが追加されている
    • myfunctionという作成したFunctionと同名のイメージが追加されている
    • <none>myfunctionの前回のイメージ
% docker images
REPOSITORY             TAG       IMAGE ID       CREATED         SIZE
heroku/pack            20        822ae55e45ce   3 hours ago     567MB
<none>                 <none>    74806d6c3d7b   41 years ago    710MB
myfunction             latest    c871af01d206   41 years ago    710MB
heroku/buildpacks      20        094f2b3353e5   41 years ago    1.54GB
  • Dockerのコンテナ
    • myfunctionイメージでコンテナが起動している
% docker ps
CONTAINER ID   IMAGE        COMMAND              CREATED         STATUS         PORTS                                            NAMES
fd1e377bacb2   myfunction   "/cnb/process/web"   7 minutes ago   Up 6 minutes   0.0.0.0:8080->8080/tcp, 0.0.0.0:9229->9229/tcp   myfunction

3.7. Java11を試みた

  • pom.xmlでバージョン指定している箇所を修正
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <java.version>11</java.version>
    </properties>
  • ローカルでmvnw clean packageして問題ないことを確認
  • sfdx run:function:start してみる
    • 以下のようにエラーで落ちた
% sfdx run:function:start
Building myfunction
20: Pulling from heroku/buildpacks
Digest: sha256:e007b9a6a71bfdbb80e412cae139d46bc98ffa580e3e780f653e89b3055be9b6
Status: Image is up to date for heroku/buildpacks:20
20: Pulling from heroku/pack
Digest: sha256:694f287e23692b3914d32aaa9c0227fc95359c16bc12ef68f8251ab3a7a6c706
Status: Image is up to date for heroku/pack:20
===> DETECTING
======== Output: heroku/ruby@0.0.1 ========
no
err:  heroku/ruby@0.0.1 (1)
heroku/jvm                  0.1.8
heroku/maven                0.2.5
heroku/jvm-function-invoker 0.5.3
===> ANALYZING
Restoring metadata for "heroku/jvm:jre" from app image
Restoring metadata for "heroku/jvm:jdk" from cache
Restoring metadata for "heroku/jvm:utils" from cache
Restoring metadata for "heroku/maven:maven-repository" from cache
Restoring metadata for "heroku/jvm-function-invoker:bundle" from app image
Restoring metadata for "heroku/jvm-function-invoker:opt" from app image
Restoring metadata for "heroku/jvm-function-invoker:runtime" from app image
===> RESTORING
Restoring data for "heroku/jvm:jdk" from cache
Restoring data for "heroku/jvm:utils" from cache
Restoring data for "heroku/maven:maven-repository" from cache
Restoring data for "heroku/jvm-function-invoker:runtime" from cache
===> BUILDING
[Installing Java]
JDK 1.8 installed from cache
JRE 1.8 installed from cache
[Installing Maven]
[INFO] Maven wrapper detected, skipping installation.
[Executing Maven]
[INFO] $ ./mvnw -DskipTests clean install
[INFO] Scanning for projects...
[INFO] 
[INFO] --
---------------------< com.example:myfunction >-----------------------
[
INFO] Building myfunction 1.0-SNAPSHOT
[INFO] --------------
------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- maven-
clean-plugin:3.1.0:clean (default-clean) @ myfunction ---
[INFO] Deleting /workspace/target
[INFO] 
[INFO] --- maven-resources-plugin:3.0.2
:resources (default-resources) @ myfunction ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip
 non existing resourceDirectory /workspace/src/main/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ myfunction ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 4 source files to /workspace/target/classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.146 s
[INFO] Finished at: 2021-09-30T04:08:34Z
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:compile (default-compile) on project myfunction: Fatal error compiling: invalid target release: 11 -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException
[ERROR: Failed to build app with Maven]
We're sorry this build is failing! If you can't find the issue in application code,
please submit a ticket so we can help: https://help.heroku.com/
ERROR: failed to build: exit status 1
ExitError: EEXIT: 0
    at Object.exit (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@oclif/errors/lib/index.js:19:11)
    at EventEmitter.<anonymous> (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@salesforce/plugin-functions/lib/commands/run/function/start.js:59:30)
    at EventEmitter.emit (events.js:400:28)
    at EventEmitter.emit (domain.js:470:12)
    at Interface.<anonymous> (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@heroku/functions-core/dist/benny.js:106:39)
    at Interface.emit (events.js:400:28)
    at Interface.emit (domain.js:470:12)
    at Interface._onLine (readline.js:364:10)
    at Interface._normalWrite (readline.js:509:12)
    at Socket.ondata (readline.js:216:10) {
  oclif: { exit: 0 },
  code: 'EEXIT'
}
ExitError: EEXIT: 0
    at Object.exit (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@oclif/errors/lib/index.js:19:11)
    at EventEmitter.<anonymous> (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@salesforce/plugin-functions/lib/commands/run/function/start.js:59:30)
    at EventEmitter.emit (events.js:400:28)
    at EventEmitter.emit (domain.js:470:12)
    at Interface.<anonymous> (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@heroku/functions-core/dist/benny.js:106:39)
    at Interface.emit (events.js:400:28)
    at Interface.emit (domain.js:470:12)
    at Interface._onLine (readline.js:364:10)
    at Interface._normalWrite (readline.js:509:12)
    at Socket.ondata (readline.js:216:10) {
  oclif: { exit: 0 },
  code: 'EEXIT'
}
ExitError: EEXIT: 0
    at Object.exit (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@oclif/errors/lib/index.js:19:11)
    at EventEmitter.<anonymous> (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@salesforce/plugin-functions/lib/commands/run/function/start.js:59:30)
    at EventEmitter.emit (events.js:400:28)
    at EventEmitter.emit (domain.js:470:12)
    at Interface.<anonymous> (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@heroku/functions-core/dist/benny.js:106:39)
    at Interface.emit (events.js:400:28)
    at Interface.emit (domain.js:470:12)
    at Interface._onLine (readline.js:364:10)
    at Interface._normalWrite (readline.js:509:12)
    at Socket.ondata (readline.js:216:10) {
  oclif: { exit: 0 },
  code: 'EEXIT'
}
ExitError: EEXIT: 0
    at Object.exit (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@oclif/errors/lib/index.js:19:11)
    at EventEmitter.<anonymous> (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@salesforce/plugin-functions/lib/commands/run/function/start.js:59:30)
    at EventEmitter.emit (events.js:400:28)
    at EventEmitter.emit (domain.js:470:12)
    at Interface.<anonymous> (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@heroku/functions-core/dist/benny.js:106:39)
    at Interface.emit (events.js:400:28)
    at Interface.emit (domain.js:470:12)
    at Interface._onLine (readline.js:364:10)
    at Interface._normalWrite (readline.js:509:12)
    at Socket.ondata (readline.js:216:10) {
  oclif: { exit: 0 },
  code: 'EEXIT'
}
ExitError: EEXIT: 0
    at Object.exit (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@oclif/errors/lib/index.js:19:11)
    at EventEmitter.<anonymous> (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@salesforce/plugin-functions/lib/commands/run/function/start.js:59:30)
    at EventEmitter.emit (events.js:400:28)
    at EventEmitter.emit (domain.js:470:12)
    at Interface.<anonymous> (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@heroku/functions-core/dist/benny.js:106:39)
    at Interface.emit (events.js:400:28)
    at Interface.emit (domain.js:470:12)
    at Interface._onLine (readline.js:364:10)
    at Interface._normalWrite (readline.js:509:12)
    at Socket.ondata (readline.js:216:10) {
  oclif: { exit: 0 },
  code: 'EEXIT'
}
ExitError: EEXIT: 0
    at Object.exit (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@oclif/errors/lib/index.js:19:11)
    at EventEmitter.<anonymous> (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@salesforce/plugin-functions/lib/commands/run/function/start.js:59:30)
    at EventEmitter.emit (events.js:400:28)
    at EventEmitter.emit (domain.js:470:12)
    at Interface.<anonymous> (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@heroku/functions-core/dist/benny.js:106:39)
    at Interface.emit (events.js:400:28)
    at Interface.emit (domain.js:470:12)
    at Interface._onLine (readline.js:364:10)
    at Interface._normalWrite (readline.js:509:12)
    at Socket.ondata (readline.js:216:10) {
  oclif: { exit: 0 },
  code: 'EEXIT'
}
    Error: Build exited with: executing lifecycle: failed with status code: 145
Choose a JDK
Create a system.properties file in the root of your project directory and set java.runtime.version=1.8.
  • system.propertiesファイルを作成して、java.runtime.versionを指定する
% echo "java.runtime.version=11" > system.properties
% cat system.properties 
java.runtime.version=11
% ls
mvnw			pom.xml			src			target
mvnw.cmd		project.toml		system.properties
  • sfdx run:function:start してみる
    • 以下のようにJDK 11がインストールされたログが表示された
    • 正常に起動して、functionの呼び出しも成功した
[Installing Java]
JDK 11 installed
JRE 11 installed

3.8. Java17を試みた

  • java.runtime.version=17 も正常に動作した
[Installing Java]
JDK 17 installed
JRE 17 installed

(追記)

3.9. キャッシュのクリア

  • イメージを削除した後で再度作成する場合など、キャッシュが残っていて正常に動作しない場合があった
    • 事象が発生した例
      • Java8でイメージを作成して起動
      • Java11でイメージを作成して起動
      • イメージを削除
      • Java11でイメージを作成しようとしたら、起動しなかった
  • 以下のコマンドでキャッシュをクリアしてイメージを作成して起動する
    • sfdx run:function:start -v --clear-cache

4. 試せなかったこと

  • Functionのデプロイ
  • ApexからのFunction実行

5. 参考

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?