应用程序间通信

本主题介绍一个 Snowflake Native App 可以如何利用应用程序间通信 (IAC) 与另一个 Snowflake Native App 通信。

应用程序间通信:概述

应用程序间通信 (IAC) 允许 Snowflake Native App 通过提供对其他应用程序可以调用的函数和过程的访问权限,在同一使用者账户中为其他 Snowflake Native Apps 提供附加功能。

例如,解析客户 IDs 的 Snowflake Native App 可以通过联接来自不同供应商的数据集,帮助其他 Snowflake Native Apps 增强客户数据。

IAC 为两个或多个独立应用程序提供相互通信的基础设施,同时尊重其管理和安全需求。应用程序开发者可以通过执行以下操作为其应用程序启用 IAC:

  • 创建接口

  • 使用应用程序角色控制对接口的访问。

  • 选择同步或异步交互。同步交互使用其他应用程序可以直接调用的存储过程或函数,而异步交互提供对存储在表或视图中的请求结果的访问权限,其他应用程序可以轮询这些表或视图以查看结果。

术语

IAC 使用以下术语:

客户端

发起连接请求并调用服务器应用程序函数和过程的应用程序。

服务器

利用应用程序角色提供对其函数和过程的访问权限的应用程序。

使用者

安装客户端和服务器应用程序的用户。

应用程序配置

客户端应用程序用于请求服务器应用程序名称的 SQL 对象。IAC 使用 APPLICATION_NAME 类型的应用程序配置来存储服务器应用程序名称。

应用程序规范

客户端应用程序为请求连接到服务器应用程序而创建的 SQL 对象。IAC 使用 CONNECTION 类型的应用程序规范。有关应用程序规范的信息,请参阅 应用程序规范概述

应用程序间通信的工作流程

建立和使用连接涉及客户端应用程序和服务器应用程序之间的握手过程。

  1. 从服务器应用程序提供商处获取应用程序角色名称:客户端应用程序提供商与 Snowflake 外部的服务器应用程序提供商协调,确定在连接规范中请求哪些服务器应用程序角色。

  2. 确定目标应用程序:客户端应用程序创建一个配置定义对象,以请求服务器应用程序的名称。使用者检测传入请求,并通过配置对象向客户端应用程序提供服务器应用程序名称。

  3. 请求并批准连接:客户端应用程序创建应用程序规范以请求连接到服务器应用程序,使用者批准连接请求。

  4. 与服务器应用程序通信:客户端应用程序调用服务器应用程序的过程或函数。

确定目标应用程序

在客户端应用程序可以与服务器应用程序通信之前,它必须首先确定应用程序的确切名称。由于使用者可以在安装过程中为应用程序选择自定义名称,因此客户端应用程序必须首先确定服务器应用程序的确切名称。

客户端应用程序的安装脚本会创建一个 CONFIGURATION DEFINITION 对象以请求此信息。

以下示例展示了客户端应用程序的安装脚本如何创建 CONFIGURATION DEFINITION 对象来请求服务器应用程序的名称:

ALTER APPLICATION
  SET CONFIGURATION DEFINITION my_server_app_name_configuration
    TYPE = APPLICATION_NAME
    LABEL = 'Server App'
    DESCRIPTION = 'Request for an app that will provide access to server procedures and functions. The server app version must be greater than or equal to 3.2.'
    APPLICATION_ROLES = (my_server_app_role);
Copy

以下示例展示使用者如何检查传入的配置定义请求:

SHOW CONFIGURATIONS IN APPLICATION my_server_app_name;
Copy

此命令返回的结果类似于以下内容:

name                             | created_on              | updated_on              | type               | ...
my_server_app_name_configuration | 2026-02-09 10:00:00.000 | 2026-02-09 10:00:00.000 | APPLICATION_NAME   | ...

然后,使用者使用以下命令提供服务器应用程序名称:

ALTER APPLICATION my_client_app_name
  SET CONFIGURATION my_server_app_name_configuration
  VALUE = MY_SERVER_APP_NAME;
Copy

请求并批准连接

一旦客户端应用程序获得了服务器应用程序的名称,它就会创建一个 APPLICATION SPECIFICATION 来请求连接到服务器应用程序。请注意,应用程序角色名称是通过 Snowflake 外部的离线通信获取的。

以下示例演示如何创建 APPLICATION SPECIFICATION 来连接到名为 my_server_app_name 的服务器应用程序:

ALTER APPLICATION SET SPECIFICATION my_server_app_name_connection_specification
  TYPE = CONNECTION
  LABEL = 'Server App'
  DESCRIPTION = 'Request for an app that will provide access to server procedures and functions. The server app version must be greater than or equal to 3.2.'
  SERVER_APPLICATION = MY_SERVER_APP_NAME -- server name obtained from Step 1
  SERVER_APPLICATION_ROLES = (my_server_app_role);
Copy

通过创建应用程序规范,客户端应用程序请求被授予应用程序规范中指定的服务器应用程序角色。

备注

应用程序规范中给定的 LABELDESCRIPTION 值必须与在第 1 步中创建的 CONFIGURATION DEFINITION 对象中给定的 LABELDESCRIPTION 值匹配。如果值不匹配,则连接将无法在 Snowsight 中正常显示。

要创建高效的连接工作流程,我们建议客户端应用程序在 before_configuration_change 同步回调中创建应用程序规范。此回调在运行 ALTER APPLICATION SET CONFIGURATION VALUE 命令时运行。有关回调的信息,请参阅 回调。有关在 before_configuration_change 同步回调中创建应用程序规范的示例安装脚本,请参阅 示例

客户端应用程序创建应用程序规范后,使用者可以查看并批准或拒绝连接请求。

使用 SQL 批准连接请求

以下示例展示了使用者如何使用 SQL 批准连接请求:

ALTER APPLICATION my_server_app_name
  APPROVE SPECIFICATION my_server_app_name_connection_specification
  SEQUENCE_NUMBER = 1;
Copy

使用 Snowsight 批准连接请求

要在 Snowsight 中查看和批准连接请求,请执行以下操作:

  1. 登录 Snowsight

  2. 选择应用程序。标题为 Application connections 的部分显示在 Configurations 下。每个待处理的连接都会显示连接的名称或标签、连接的简要描述以及 Review 按钮。

  3. 点击 Review 按钮。此时将显示连接请求的详细信息。

  4. Select from your apps 中选择目标应用程序。

  5. 点击 Next。将显示以下信息:

    • 一个图表,显示客户端应用程序将连接到服务器应用程序,以及应用程序将使用的角色。

    • 连接的详细信息。

    • 将授予客户端应用程序的服务器权限的子集。有关 IAC 安全注意事项的信息,请参阅 安全注意事项

    • 一个 Approve Connection 切换开关。开关设置为 On

  6. 要批准连接,请将切换开关设置为 On,然后点击 Save。更新的连接列表随即显示连接的状态。

  7. 要拒绝连接,请将切换开关切换到 Off

  8. 要退出审查页面而不批准或拒绝连接,请点击 Cancel 按钮。

批准后

当使用者批准连接请求时,Snowflake Native App Framework 会将请求的服务器应用程序角色授予客户端应用程序。批准还会授予服务器应用程序对客户端应用程序的 USAGE 权限。这使服务器应用程序可以知道哪些客户端应用程序连接到它。

当使用者批准连接请求时,将分别在客户端和服务器应用程序中触发以下回调:

这些回调允许服务器和客户端应用程序在建立连接时执行其他操作。

有关批准应用程序规范的更多信息,请参阅以下主题:

与服务器应用程序通信

建立连接并授予客户端应用程序请求的服务器应用程序角色后,客户端应用程序就可以与服务器应用程序通信。

备注

在调用服务器应用程序方法之前,客户端应用程序应在运行时从批准的应用程序规范中检索服务器应用程序的名称,以确保在重命名服务器应用程序时使用正确的名称。以下示例演示如何在运行时检索服务器应用程序的名称:

SHOW APPROVED SPECIFICATIONS ->>
  SELECT PARSE_JSON("definition"):"SERVER_APPLICATION"::STRING
  FROM $1
  WHERE "name" = 'MY_SERVER_APP_NAME_CONNECTION_SPECIFICATION';
Copy

客户端应用程序可以与服务器应用程序同步或异步通信。

  • 同步通信涉及直接调用服务器应用程序的过程或函数。

  • 异步通信涉及使用存储在数据对象(如表)中的队列。例如,服务器应用程序可以提供一个过程,将记录作为请求插入到表中,然后服务器应用程序会定期处理这些记录。然后,客户端应用程序可以使用服务器提供的不同过程来检查表中的结果。

以下同步操作示例展示了客户端应用程序使用 Python 调用服务器应用程序的过程:

session.call("server_app_name.customer_schema.get_customer_data", customer_id);
Copy

以下异步操作示例展示了客户端应用程序使用 Python 调用服务器应用程序的过程。客户端应用程序调用服务器应用程序的过程,该过程会在表中创建一个请求,然后由服务器应用程序处理。客户端应用程序可以轮询表,以查看结果的更新记录。

session.call("server_app_name.customer_schema.request_customer_data_async", customer_id);
Copy

然后,客户端应用程序可以轮询表,以查看结果的更新记录:

session.call("server_app_name.customer_schema.check_customer_data_requests_async", customer_id);
Copy

管理连接

要在 Snowsight 中查看现有连接,请执行以下操作:

  1. 登录 Snowsight

  2. 在导航菜单中,选择 Catalog » Apps

  3. 选择应用程序。所有应用程序连接都显示在标题为 Configurations 的部分下。在该部分下方,有一个子部分,标题为 Application connections

  4. 要修改连接,请点击该连接的铅笔图标。您可以更改以下内容:

    • 哪个应用程序连接到该应用程序

    • 连接的批准状态

  5. 要查看连接的应用程序,请点击 View app 按钮。

  6. 要更改连接的安全设置,请点击齿轮图标。

安全注意事项

在批准规范请求时,使用者应注意,授予服务器应用程序对客户端应用程序的访问权限可能会提升客户端应用程序的权限。例如,如果服务器应用程序具有外部访问权限,则客户端应用程序可能会通过服务器应用程序间接访问互联网或其他外部资源。如果服务器应用程序是另一个服务器应用程序的客户端应用程序,则客户端应用程序可能能够通过第一个服务器应用程序访问另一个服务器应用程序的资源。

在批准连接之前,使用者应检查服务器应用程序的功能和权限。使用管理员角色(例如,ACCOUNTADMIN)来检查服务器的功能。使用权限较低的角色检查服务器不会显示服务器的所有功能和权限。使用者应注意,服务器应用程序代码对使用者不可见,并且使用者批准连接后,可以更改服务器应用程序权限和功能。

示例 SQL 命令用于检查服务器应用程序的功能和权限,包括但不限于以下命令:

SQL 参考

以下 SQL 命令用于管理应用程序间通信。

回调

Snowflake Native App Framework 提供生命周期回调,以帮助管理应用间通信的工作流程。这些回调允许应用程序对配置、连接和规范的变更做出响应。要使用回调,请在应用的清单文件的 lifecycle_callbacks 部分中注册它们。

有关回调的一般信息,请参阅 回调

配置回调

设置或取消设置配置值时会触发这些回调。一个常见的用例是使用 before_configuration_change 回调,以在使用者提供服务器应用程序名称时自动创建连接规范。

validate_configuration_change

一个同步回调,作为 ALTER APPLICATION SET CONFIGURATION VALUE 命令的一部分被调用。允许应用程序对提供的值执行自定义验证。如果回调返回错误,则命令失败,并且不会设置新值。

before_configuration_change

一个同步回调,作为 ALTER APPLICATION SET CONFIGURATION VALUEALTER APPLICATION UNSET CONFIGURATION 命令的一部分被调用。允许应用程序在保存配置值之前根据配置值执行操作。

after_configuration_change

一个异步回调,在 ALTER APPLICATION SET CONFIGURATION VALUEALTER APPLICATION UNSET CONFIGURATION 命令完成后被调用。允许应用程序对变更做出反应,例如出于通知或跟踪目的。

连接回调

当连接状态变化时,会触发这些回调,例如连接建立、被拒绝、断开,或是当连接的应用程序被删除时。

after_server_connection_change

一个异步回调,在客户端应用程序中由任何影响连接状态的操作触发,包括批准、拒绝或删除规范,或删除服务器应用程序。

after_client_connection_change

一个异步回调,在服务器应用程序中由任何影响连接状态的操作触发,包括批准、拒绝或删除规范,或删除客户端应用程序。

after_server_version_change

一个异步回调,在服务器应用程序的版本或补丁号更改后,在客户端应用程序中被调用。允许客户端应用程序对升级或降级做出反应。

示例

以下示例演示如何配置应用程序以使用应用程序间通信。

示例:安装脚本和清单文件

以下示例显示了客户端应用程序的安装脚本 (setup.sql):

CREATE OR ALTER VERSIONED SCHEMA app_schema;

-- create a callback that creates the connection request before the config value of the server name is saved
CREATE OR REPLACE PROCEDURE app_schema.before_config_change_callback(config_name STRING, config_value STRING)
RETURNS STRING
LANGUAGE SQL
AS
$$
DECLARE
    spec_name VARCHAR;
    existing_target VARCHAR;
BEGIN
    IF (config_value IS NOT NULL AND config_name = 'MY_SERVER_APP_NAME_CONFIGURATION') THEN
        SHOW SPECIFICATIONS;
        SELECT PARSE_JSON("definition"):SERVER_APPLICATION::STRING
            INTO existing_target
            FROM TABLE(RESULT_SCAN(LAST_QUERY_ID()));

        IF(existing_target IS NOT NULL AND UPPER(existing_target) != UPPER(config_value)) THEN
            EXECUTE IMMEDIATE 'ALTER APPLICATION DROP SPECIFICATION CONNECTION_' || UPPER(existing_target);
        END IF;

        spec_name := 'CONNECTION_' || UPPER(config_value);
        EXECUTE IMMEDIATE
        'ALTER APPLICATION SET SPECIFICATION ' || spec_name || '
            TYPE = CONNECTION
            LABEL = ''Server App''
            DESCRIPTION = ''Request for an app that will provide access to server procedures and functions. The server app version must be greater than or equal to 3.2.''
            SERVER_APPLICATION = ' || config_value || '
            SERVER_APPLICATION_ROLES = (my_server_app_role)';
    END IF;
RETURN 'success';
END;
$$;

CREATE APPLICATION ROLE IF NOT EXISTS client_app_user;
GRANT USAGE ON SCHEMA app_schema TO APPLICATION ROLE client_app_user;
ALTER APPLICATION SET CONFIGURATION DEFINITION my_server_app_name_configuration
    TYPE = APPLICATION_NAME
    LABEL = 'Server App'
    DESCRIPTION = 'Request for an application that will provide access to server procedures and functions. The server app version must be greater than or equal to 3.2'
    APPLICATION_ROLES = (client_app_user);
Copy

以下示例显示了客户端应用程序的清单文件 (manifest.yml):

manifest_version: 2

artifacts:
  setup_script: setup.sql

lifecycle_callbacks:
    before_configuration_change: app_schema.before_config_change_callback
Copy

请注意上述代码示例的以下几点:

  • before_configuration_change 回调中,应用程序会检查是否存在与配置的先前值匹配的现有连接规范,如果存在,则将其删除。然后,回调会为新提供的服务器应用程序名称创建新的连接规范。设置服务器名称后创建新连接可防止创建重复的连接规范。

示例:应用程序之间的异步通信

以下示例演示如何在服务器应用程序的安装脚本 (setup.sql) 中创建过程用于异步通信。服务器应用程序创建处理队列表,并通过应用程序角色向客户端应用程序提供两个过程:submit_request,将请求添加到队列中;fetch_response,检索已完成请求的结果。服务器应用程序定期使用 process_requests 过程来处理所有待处理请求。

CREATE TABLE IF NOT EXISTS app_schema.processing_queue (
  request_id NUMBER AUTOINCREMENT,
  operation STRING,
  input STRING,
  status STRING DEFAULT 'PENDING',
  response STRING DEFAULT ''
);

CREATE OR REPLACE PROCEDURE app_schema.submit_request(operation STRING, input STRING)
RETURNS STRING
LANGUAGE SQL
EXECUTE AS OWNER
AS
$$
BEGIN
    INSERT INTO app_schema.processing_queue (operation, input) VALUES (:operation, :input);
    RETURN 'Request submitted successfully';
END;
$$;

CREATE OR REPLACE PROCEDURE app_schema.process_requests()
RETURNS STRING
LANGUAGE SQL
EXECUTE AS OWNER
AS
$$
DECLARE
    -- Cursor to find all PENDING requests
    c1 CURSOR FOR SELECT * FROM app_schema.processing_queue WHERE status = 'PENDING';
    result STRING;
BEGIN
    FOR request IN c1 DO

        IF (request.operation = 'OPERATION_X') THEN
            -- assuming there is a UDF func_x(input) to perform operation_x
            result := (SELECT func_x(:request.input));
        END IF;

        -- update the processing queue with the result
        LET stmt STRING :=
            'UPDATE app_schema.processing_queue SET status = 'DONE', response = ' ||
            result ||
            ' WHERE request_id = ' ||
            request.request_id;
        EXECUTE IMMEDIATE (:stmt);

    END FOR;

    RETURN 'Processed pending requests.';
END;
$$;

CREATE OR REPLACE PROCEDURE app_schema.fetch_response(operation STRING, input STRING)
RETURNS STRING
LANGUAGE SQL
EXECUTE AS OWNER
AS
$$
BEGIN
    LET res STRING := (SELECT response FROM app_schema.processing_queue WHERE operation = :operation AND input = :input);
    RETURN res;
END;
$$;

CREATE APPLICATION ROLE IF NOT EXISTS my_server_app_role;
GRANT USAGE ON SCHEMA app_schema TO APPLICATION ROLE my_server_app_role;
GRANT USAGE ON PROCEDURE app_schema.submit_request(string, string) TO APPLICATION ROLE my_server_app_role;
GRANT USAGE ON PROCEDURE app_schema.process_requests() TO APPLICATION ROLE my_server_app_role;
GRANT USAGE ON PROCEDURE app_schema.fetch_response(string, string) TO APPLICATION ROLE my_server_app_role;
Copy