Alternate to "tctl admin cluster add-search-attributes" to add new search attributes

Usecase
Want to add custom search attributes.
I’m currently doing it with the below command
tctl admin cluster add-search-attributes --name mySA --type String

Question
Is there any other way to do the same?
As I won’t be allowed to execute commands in higher environments.

It’s not exposed via SDKs currently, but the the admin service api is available here.

You would have to create a gRPC client
to call

NewAdminServiceClient and use AddSearchAttributesRequest

like hows done in tctl here.

We are currently working on exposing this functionality to SDKs. For now, the only way is to use tctl ro call Admin API as @tihomir pointed out.

I’m trying to create client for only the add search attributes call.

Below is my proto file

syntax = "proto3";

package grpc.bc.cd.health;
option java_multiple_files = true;

message AddSearchAttributesRequest {
    map<string, temporal.api.enums.v1.IndexedValueType> search_attributes = 1;
    string index_name = 2;
    bool skip_schema_update = 3;
}

message AddSearchAttributesResponse {
}

service AdminService {
rpc AddSearchAttributes (AddSearchAttributesRequest) returns (AddSearchAttributesResponse) {
    }
}

From where can I get this → temporal.api.enums.v1.IndexedValueType ?

From where can I get this → temporal.api.enums.v1.IndexedValueType ?

That fixed the problem and I was able to generate the Java classes.

Below is my code. I’m getting Exception in thread “main” io.grpc.StatusRuntimeException: UNKNOWN. Want to confirm whether this code is good? I’m new to gRPC.

    ManagedChannel channel = ManagedChannelBuilder.forTarget("my-temporal-url")
            .usePlaintext()
            .build();

    AdminServiceGrpc.AdminServiceBlockingStub adminServiceBlockingStub = AdminServiceGrpc.newBlockingStub(channel);

    adminServiceBlockingStub.addSearchAttributes(
            Temporaladmin.AddSearchAttributesRequest
                    .newBuilder()
                    .putSearchAttributes("MySearchAttrKey", Temporaladmin.IndexedValueType.INDEXED_VALUE_TYPE_BOOL)
            .build()
    );

I also tried to create the channel like below but same error.

public ManagedChannel getChannel() {
        NettyChannelBuilder builder =
                NettyChannelBuilder.forTarget("my-temporal-url")
                        .defaultLoadBalancingPolicy("round_robin")
                        .maxInboundMessageSize(25_000_000)
                        .usePlaintext();
        return builder.build();
    }

Using NettyChannelBuilder should work. See how it’s used here.

Wondering about "my-temporal-url", are you able to perform a health check on your channel once its created, for example here.

  1. Replacing .usePlaintext() with `.useTransportSecurity(); fixed the connectivity issues.
  2. Post that I got "UNIMPLEMENTED" exception. Solved this by setting the package to temporal.server.api.adminservice.v1 in proto file.

Here’s the final proto and java code.

Proto

syntax = "proto3";
package temporal.server.api.adminservice.v1;

enum IndexedValueType {
    INDEXED_VALUE_TYPE_UNSPECIFIED = 0;
    INDEXED_VALUE_TYPE_TEXT = 1;
    INDEXED_VALUE_TYPE_KEYWORD = 2;
    INDEXED_VALUE_TYPE_INT = 3;
    INDEXED_VALUE_TYPE_DOUBLE = 4;
    INDEXED_VALUE_TYPE_BOOL = 5;
    INDEXED_VALUE_TYPE_DATETIME = 6;
}

message AddSearchAttributesRequest {
    map<string, IndexedValueType> search_attributes = 1;
    string index_name = 2;
    bool skip_schema_update = 3;
}

message AddSearchAttributesResponse {
}

service AdminService {
    rpc AddSearchAttributes (AddSearchAttributesRequest) returns (AddSearchAttributesResponse);
}

Java

package temporal.server.api.adminservice.v1;

import io.grpc.ManagedChannel;
import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder;

public class Service {
    public static void main(String[] args) {
        Service service = new Service();
        String serverUrl = "serverUrl";
        String key = "search_attr_key";
        Temporaladmin.IndexedValueType type = Temporaladmin.IndexedValueType.INDEXED_VALUE_TYPE_TEXT;
        service.addSearchAttr(key, type, serverUrl);
    }

    private void addSearchAttr(String key, Temporaladmin.IndexedValueType type, String serverUrl) {

        ManagedChannel channel = getChannel(serverUrl);

        AdminServiceGrpc.AdminServiceBlockingStub adminServiceBlockingStub = AdminServiceGrpc.newBlockingStub(channel);

        adminServiceBlockingStub.addSearchAttributes(
                Temporaladmin.AddSearchAttributesRequest
                        .newBuilder()
                        .putSearchAttributes(key, type)
                        .build()
        );

    }

    public ManagedChannel getChannel(String serverUrl) {
        NettyChannelBuilder builder =
                NettyChannelBuilder.forTarget(serverUrl)
                        .defaultLoadBalancingPolicy("round_robin")
                        .maxInboundMessageSize(25_000_000)
                        .useTransportSecurity();
        return builder.build();
    }
}
1 Like

What is the purpose of frontend.validSearchAttributes in dynamic config ?

It was removed from dynamic config like a year ago, and if you still have it there, it is not used.

1 Like

@alex you mentioned year ago that you guys are working on exposing this attribute adding to SDKs. Did you manage to release it?

I believe it is available through OperatorService.

1 Like

Thanks @maxim, OperatorServiceStubs delivers the feature.