# distutils: language = c++
# cython: embedsignature = True
# cython: language_level = 3
# cython: c_string_encoding = default
# coding=UTF-8
# Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import asyncio
import concurrent
import inspect
import logging
import json
import os
import pickle
import traceback
import threading
import traceback
import uuid
from pathlib import Path
from dataclasses import asdict
from typing import List, Optional, Tuple, Union, Callable
from cython.operator import dereference, postincrement
from cpython.exc cimport PyErr_CheckSignals

import yr
from yr.config import SchedulingAffinityType, FunctionGroupOptions, ResourceGroupOptions, GroupOptions
from yr.common.types import GroupInfo, CommonStatus, Resource, Resources, BundleInfo, Option, RgInfo, ResourceGroupUnit
from yr.common import constants
from yr.common.utils import generate_random_id, create_new_event_loop, refresh_env
from yr.config_manager import ConfigManager
from yr.err_type import ErrorCode, ModuleCode, ErrorInfo
from yr.executor.executor import Executor
from yr.executor.instance_manager import InstanceManager, InstancePackage
from yr.libruntime_pb2 import FunctionMeta, LanguageType, InvokeType, ApiType, Signal
from yr.object_ref import ObjectRef
from yr import log
from yr.common.utils import GaugeData, UInt64CounterData, DoubleCounterData
from yr.device import DataType, DeviceBufferParam, DataInfo
from yr.base_runtime import (ExistenceOpt, WriteMode, CacheType, ConsistencyType, SetParam, MSetParam, CreateParam,
                             GetParam, GetParams, AlarmInfo, AlarmSeverity)
from yr import runtime_env
from yr import port_forwarding
from yr.checkpoint import SnapstartInfo, SnapstartResponse
from yr.exception import YRInvokeError, _cause_to_str
from yr.stream import (Element, ProducerConfig, SubscriptionConfig,
                       SubscriptionType)
from yr.accelerate.shm_broadcast import Handle, MessageQueue, decode, ResponseStatus
from yr.accelerate.executor import ACCELERATE_WORKER, Worker
from cpython.bytes cimport PyBytes_AS_STRING, PyBytes_FromStringAndSize
from libc.stdint cimport int64_t, uint64_t
from libcpp cimport bool
from libcpp.memory cimport make_shared, nullptr, shared_ptr, dynamic_pointer_cast
from libcpp.pair cimport pair
from libcpp.string cimport string
from libcpp.unordered_map cimport unordered_map
from libcpp.unordered_set cimport unordered_set
from libcpp.vector cimport vector
from libc.string cimport memcpy

from yr.includes.libruntime cimport (CApiType, CSignal, CBuffer, CDataObject, CElement,
CErrorCode, CErrorInfo, CFunctionMeta, CInternalWaitResult, CInvokeArg,
CInvokeOptions, CInvokeType, CModuleCode,
CLanguageType, CLibruntimeConfig,
CLibruntimeManager,move,CLibruntime, CGroupOptions,
CProducerConf, CStreamConsumer,
CStreamProducer, CSubscriptionConfig,
CSubscriptionType,
CExistenceOpt, CSetParam, CMSetParam, CCreateParam, CStackTraceInfo, CWriteMode, CCacheType, CConsistencyType,
CGetParam, CGetParams,
CMultipleReadResult, CDevice, CMultipleDelResult, CUInt64CounterData, CDoubleCounterData, NativeBuffer, StringNativeBuffer, SharedBuffer as CSharedBuffer, CInstanceOptions, CSnapOptions, CSnapStartOptions, CSnapstartInfo, CSnapstartResponse, CSnapType, CGaugeData, CTensor, CDataType, CResourceUnit, CAlarmInfo, CAlarmSeverity, CFunctionGroupOptions, CBundleAffinity, CFunctionGroupRunningInfo, CFiberEvent,
CClusterAccessInfo, AutoGetClusterAccessInfo, CResourceGroupSpec, CResourceGroupOptions, CAccelerateMsgQueueHandle, QueryNamedInsResponse, CResourceGroupUnit, CRgInfo, CBundleInfo, CResources, CResource, CType, CScalar)

include "includes/affinity.pxi"
include "includes/buffer.pxi"
include "includes/serialization.pxi"

_logger = logging.getLogger(__name__)

_serialization_ctx = None
_eventloop_for_default_cg = None
_thread_for_default_cg = None
_actor_is_async = False

class GeneratorEndError(RuntimeError):
    """GeneratorEndError stream error"""
    def __init__(self, message):
        super().__init__(message)
        self.message = message

    def __str__(self):
        return f"generator stop : {self.message}"

cdef error_code_from_cpp(CErrorCode code):
    if code == CErrorCode.ERR_GENERATOR_FINISHED:
        return ErrorCode.ERR_GENERATOR_FINISHED

cdef CErrorCode error_code_from_py(error_code: ErrorCode):
    cdef CErrorCode c_error_code
    c_error_code = CErrorCode.ERR_OK
    if error_code == ErrorCode.ERR_USER_CODE_LOAD:
        c_error_code = CErrorCode.ERR_USER_CODE_LOAD
    elif error_code == ErrorCode.ERR_USER_FUNCTION_EXCEPTION:
        c_error_code = CErrorCode.ERR_USER_FUNCTION_EXCEPTION
    elif error_code == ErrorCode.ERR_EXTENSION_META_ERROR:
        c_error_code = CErrorCode.ERR_EXTENSION_META_ERROR
    return c_error_code

cdef CModuleCode module_code_from_py(module_code: ModuleCode):
    cdef CModuleCode c_module_code
    c_module_code = CModuleCode.RUNTIME
    if module_code == ModuleCode.CORE:
        c_module_code = CModuleCode.CORE
    return c_module_code

cdef error_info_from_cpp(CErrorInfo c_error_info):
    if c_error_info.OK():
        return ErrorInfo()
    return ErrorInfo(c_error_info.Code(), c_error_info.MCode(), c_error_info.Msg().decode())

cdef CErrorInfo error_info_from_py(error_info: ErrorInfo):
    cdef:
        CErrorCode error_code
        CModuleCode module_code
        string msg
        CErrorInfo c_error_info = CErrorInfo()

    if error_info.error_code == ErrorCode.ERR_OK:
        return c_error_info

    error_code = error_code_from_py(error_info.error_code)
    module_code = module_code_from_py(error_info.module_code)
    msg = error_info.msg.encode()
    c_error_info = CErrorInfo(error_code, module_code, msg)
    return c_error_info

cdef check_error_info(CErrorInfo c_error_info, mesg: str):
    if c_error_info.OK():
        return
    raise RuntimeError(
        f"{mesg}, "
        f"code: {c_error_info.Code()}, "
        f"module code {c_error_info.MCode()}, "
        f"msg: {c_error_info.Msg().decode()}"
    )

cdef api_type_from_cpp(const CApiType & c_api_type):
    api_type = ApiType.Function
    if c_api_type == CApiType.FAAS:
        api_type = ApiType.Faas
    elif c_api_type == CApiType.POSIX:
        api_type = ApiType.Posix
    elif c_api_type == CApiType.SERVE:
        api_type = ApiType.Serve
    return api_type

cdef language_type_from_cpp(const CLanguageType & c_language_type):
    language_type = LanguageType.Python
    if c_language_type == CLanguageType.LANGUAGE_CPP:
        language_type = LanguageType.Cpp
    elif c_language_type == CLanguageType.LANGUAGE_PYTHON:
        language_type = LanguageType.Python
    elif c_language_type == CLanguageType.LANGUAGE_JAVA:
        language_type = LanguageType.Java
    elif c_language_type == CLanguageType.LANGUAGE_GOLANG:
        language_type = LanguageType.Golang
    elif c_language_type == CLanguageType.LANGUAGE_NODE_JS:
        language_type = LanguageType.NodeJS
    elif c_language_type == LanguageType.CSharp:
        language_type = LanguageType.CSharp
    elif c_language_type == CLanguageType.LANGUAGE_PHP:
        language_type = LanguageType.Php
    return language_type

cdef CLanguageType language_type_from_py(language_type: LanguageType):
    cdef CLanguageType c_language_type = CLanguageType.LANGUAGE_PYTHON
    if language_type == LanguageType.Cpp:
        c_language_type = CLanguageType.LANGUAGE_CPP
    elif language_type == LanguageType.Python:
        c_language_type = CLanguageType.LANGUAGE_PYTHON
    elif language_type == LanguageType.Java:
        c_language_type = CLanguageType.LANGUAGE_JAVA
    elif language_type == LanguageType.Golang:
        c_language_type = CLanguageType.LANGUAGE_GOLANG
    elif language_type == LanguageType.NodeJS:
        c_language_type = CLanguageType.LANGUAGE_NODE_JS
    elif language_type == LanguageType.CSharp:
        c_language_type = CLanguageType.LANGUAGE_CSHARP
    elif language_type == LanguageType.Php:
        c_language_type = CLanguageType.LANGUAGE_PHP
    return c_language_type

cdef CUInt64CounterData uint64_counter_data_from_py(uint64_counter_data: UInt64CounterData):
    cdef:
        CUInt64CounterData c_uint64_counter_data
    c_uint64_counter_data.name = uint64_counter_data.name
    c_uint64_counter_data.description = uint64_counter_data.description
    c_uint64_counter_data.unit = uint64_counter_data.unit
    for key, value in uint64_counter_data.labels.items():
        c_uint64_counter_data.labels.insert(pair[string, string](key, value))
    c_uint64_counter_data.value = uint64_counter_data.value
    return c_uint64_counter_data

cdef CDoubleCounterData double_counter_data_from_py(double_counter_data: DoubleCounterData):
    cdef:
        CDoubleCounterData c_double_counter_data
    c_double_counter_data.name = double_counter_data.name
    c_double_counter_data.description = double_counter_data.description
    c_double_counter_data.unit = double_counter_data.unit
    for key, value in double_counter_data.labels.items():
        c_double_counter_data.labels.insert(pair[string, string](key, value))
    c_double_counter_data.value = double_counter_data.value
    return c_double_counter_data

cdef CGaugeData gauge_data_from_py(gauge_data: GaugeData):
    cdef:
        CGaugeData c_gauge_data
    c_gauge_data.name = gauge_data.name
    c_gauge_data.description = gauge_data.description
    c_gauge_data.unit = gauge_data.unit
    for key, value in gauge_data.labels.items():
        c_gauge_data.labels.insert(pair[string, string](key, value))
    c_gauge_data.value = gauge_data.value
    return c_gauge_data

cdef CAccelerateMsgQueueHandle message_queue_handle_from_py(handle: Handle):
    cdef:
        CAccelerateMsgQueueHandle c_msg_queue_handle
    c_msg_queue_handle.worldSize = handle.n_reader
    c_msg_queue_handle.rank = handle.rank
    c_msg_queue_handle.maxChunkBytes = handle.max_chunk_bytes
    c_msg_queue_handle.maxChunks = handle.max_chunks
    c_msg_queue_handle.name = handle.name.encode()
    c_msg_queue_handle.isAsync = handle.use_async_loop
    return c_msg_queue_handle

cdef CAlarmInfo alarm_info_from_py(info: AlarmInfo):
    cdef:
        CAlarmInfo c_alarm_info
    c_alarm_info.alarmName = info.alarm_name
    if info.alarm_severity == AlarmSeverity.OFF:
        c_alarm_info.alarmSeverity = CAlarmSeverity.OFF
    elif info.alarm_severity == AlarmSeverity.INFO:
        c_alarm_info.alarmSeverity = CAlarmSeverity.INFO
    elif info.alarm_severity == AlarmSeverity.MINOR:
        c_alarm_info.alarmSeverity = CAlarmSeverity.MINOR
    elif info.alarm_severity == AlarmSeverity.MAJOR:
        c_alarm_info.alarmSeverity = CAlarmSeverity.MAJOR
    elif info.alarm_severity == AlarmSeverity.CRITICAL:
        c_alarm_info.alarmSeverity = CAlarmSeverity.CRITICAL
    else:
        c_alarm_info.alarmSeverity = CAlarmSeverity.OFF
    c_alarm_info.locationInfo = info.location_info
    c_alarm_info.cause = info.cause
    c_alarm_info.startsAt = info.starts_at
    c_alarm_info.endsAt = info.ends_at
    c_alarm_info.timeout = info.timeout
    for key, value in info.custom_options.items():
        c_alarm_info.customOptions.insert(pair[string, string](key, value))
    return c_alarm_info

cdef CSetParam set_param_from_py(set_param: SetParam):
    cdef:
        CSetParam param
    if set_param.existence == ExistenceOpt.NONE:
        param.existence = CExistenceOpt.NONE
    else:
        param.existence = CExistenceOpt.NX

    if set_param.write_mode == WriteMode.NONE_L2_CACHE:
        param.writeMode = CWriteMode.NONE_L2_CACHE
    elif set_param.write_mode == WriteMode.WRITE_THROUGH_L2_CACHE:
        param.writeMode = CWriteMode.WRITE_THROUGH_L2_CACHE
    elif set_param.write_mode == WriteMode.WRITE_BACK_L2_CACHE:
        param.writeMode = CWriteMode.WRITE_BACK_L2_CACHE
    elif set_param.write_mode == WriteMode.NONE_L2_CACHE_EVICT:
        param.writeMode = CWriteMode.NONE_L2_CACHE_EVICT
    else:
        param.writeMode = CWriteMode.NONE_L2_CACHE
    param.ttlSecond = set_param.ttl_second

    if set_param.cache_type == CacheType.MEMORY:
        param.cacheType = CCacheType.MEMORY
    elif set_param.cache_type == CacheType.DISK:
        param.cacheType = CCacheType.DISK
    else:
        param.cacheType = CCacheType.MEMORY
    return param

cdef CMSetParam m_set_param_from_py(m_set_param: MSetParam):
    cdef:
        CMSetParam param
    param.existence = CExistenceOpt.NX
    param.ttlSecond = m_set_param.ttl_second

    if m_set_param.write_mode == WriteMode.NONE_L2_CACHE:
        param.writeMode = CWriteMode.NONE_L2_CACHE
    elif m_set_param.write_mode == WriteMode.WRITE_THROUGH_L2_CACHE:
        param.writeMode = CWriteMode.WRITE_THROUGH_L2_CACHE
    elif m_set_param.write_mode == WriteMode.WRITE_BACK_L2_CACHE:
        param.writeMode = CWriteMode.WRITE_BACK_L2_CACHE
    elif m_set_param.write_mode == WriteMode.NONE_L2_CACHE_EVICT:
        param.writeMode = CWriteMode.NONE_L2_CACHE_EVICT
    else:
        param.writeMode = CWriteMode.NONE_L2_CACHE

    if m_set_param.cache_type == CacheType.MEMORY:
        param.cacheType = CCacheType.MEMORY
    elif m_set_param.cache_type == CacheType.DISK:
        param.cacheType = CCacheType.DISK
    else:
        param.cacheType = CCacheType.MEMORY
    return param

cdef CCreateParam create_param_from_py(create_param: CreateParam):
    cdef:
        CCreateParam param

    if create_param.consistency_type == ConsistencyType.PRAM:
        param.consistencyType = CConsistencyType.PRAM
    elif create_param.consistency_type == ConsistencyType.CAUSAL:
        param.consistencyType = CConsistencyType.CAUSAL
    else:
        param.consistencyType = CConsistencyType.PRAM

    if create_param.cache_type == CacheType.MEMORY:
        param.cacheType = CCacheType.MEMORY
    elif create_param.cache_type == CacheType.DISK:
        param.cacheType = CCacheType.DISK
    else:
        param.cacheType = CCacheType.MEMORY
    return param

cdef CGetParam get_param_from_py(param: GetParam):
    cdef:
        CGetParam c_get_param
    c_get_param.offset = param.offset
    c_get_param.size = param.size
    return c_get_param

cdef CGetParams get_params_from_py(params: GetParams):
    cdef:
        CGetParams c_get_params
    for get_param in params.get_params:
        c_get_param = get_param_from_py(get_param)
        c_get_params.getParams.push_back(c_get_param)
    return c_get_params

cdef CGroupOptions group_options_from_py(group_name: str, group_opts: GroupOptions):
    cdef:
        CGroupOptions c_group_options
    c_group_options.groupName = group_name.encode()
    c_group_options.timeout = group_opts.timeout
    c_group_options.sameLifecycle = group_opts.same_lifecycle
    c_group_options.strategy = group_opts.strategy
    return c_group_options

cdef CFunctionGroupOptions function_group_options_from_py(function_group_opts: FunctionGroupOptions, group_size: int):
    cdef:
        CFunctionGroupOptions c_function_group_options
    if function_group_opts.scheduling_affinity_type is None:
        c_function_group_options.bundleAffinity = CBundleAffinity.COMPACT
    elif function_group_opts.scheduling_affinity_type == SchedulingAffinityType.REQUIRED_AFFINITY_IN_EACH_BUNDLE:
        c_function_group_options.bundleAffinity = CBundleAffinity.COMPACT
    c_function_group_options.functionGroupSize = group_size
    if function_group_opts.scheduling_affinity_each_bundle_size is not None:
        c_function_group_options.bundleSize = function_group_opts.scheduling_affinity_each_bundle_size
    if function_group_opts.timeout is not None:
        c_function_group_options.timeout = function_group_opts.timeout
    return c_function_group_options

cdef CResourceGroupOptions resource_group_options_from_py(resource_group_opts: ResourceGroupOptions):
    cdef:
        CResourceGroupOptions c_resource_group_options
    c_resource_group_options.resourceGroupName = resource_group_opts.resource_group_name
    c_resource_group_options.bundleIndex = resource_group_opts.bundle_index
    return c_resource_group_options

cdef bytes_to_vector(b: bytes):
    cdef Py_ssize_t n = len(b)
    cdef const char* buf = b
    cdef vector[char] v
    v.resize(n)
    memcpy(v.data(), buf, n)
    return v

def vector_to_bytes(vector[char] v):
    return v.data()[:v.size()]

cdef function_meta_from_py(CFunctionMeta & functionMeta, func_meta: FunctionMeta):
    cdef:
        string name
        string ns
    name = func_meta.name.encode()
    ns = func_meta.ns.encode()
    functionMeta.appName = func_meta.applicationName
    functionMeta.moduleName = func_meta.moduleName
    functionMeta.funcName = func_meta.functionName
    functionMeta.className = func_meta.className
    functionMeta.languageType = language_type_from_py(func_meta.language)
    functionMeta.codeId = func_meta.codeID
    functionMeta.signature = func_meta.signature
    functionMeta.apiType = func_meta.apiType
    functionMeta.name = name
    functionMeta.ns = ns
    functionMeta.functionId = func_meta.functionID
    functionMeta.initializerCodeId = func_meta.initializerCodeID
    functionMeta.isGenerator = func_meta.isGenerator
    functionMeta.isAsync = func_meta.isAsync
    functionMeta.tensorTransportTarget = func_meta.tensorTransportTarget
    functionMeta.enableTensorTransport = func_meta.enableTensorTransport
    functionMeta.code = bytes_to_vector(func_meta.code)

cdef function_meta_from_cpp(const CFunctionMeta & function):
    cdef:
        string emptyString
    emptyString = "".encode()
    func_meta = FunctionMeta(applicationName=function.appName.decode(),
                             moduleName=function.moduleName.decode(),
                             className=function.className.decode(),
                             functionName=function.funcName.decode(),
                             language=language_type_from_cpp(function.languageType),
                             codeID=function.codeId.decode(),
                             apiType=api_type_from_cpp(function.apiType),
                             signature=function.signature.decode(),
                             name=function.name.decode(),
                             ns=function.ns.decode(),
                             initializerCodeID=function.initializerCodeId.decode(),
                             isGenerator=function.isGenerator,
                             isAsync=function.isAsync,
                             code=vector_to_bytes(function.code),
                             tensorTransportTarget=function.tensorTransportTarget,
                             enableTensorTransport=function.enableTensorTransport)
    return func_meta

cdef function_group_running_info_from_cpp(const CFunctionGroupRunningInfo & info):
    context = yr.FunctionGroupContext()
    context.rank_id = info.instanceRankId
    context.world_size = info.worldSize
    context.device_name = info.deviceName.decode()
    for i in range(info.serverList.size()):
        server_info = yr.ServerInfo()
        server_info.server_id = info.serverList[i].serverId.decode()
        for j in range(info.serverList[i].devices.size()):
            device_info = yr.DeviceInfo()
            device_info.device_id = info.serverList[i].devices[j].deviceId
            device_info.device_ip = info.serverList[i].devices[j].deviceIp.decode()
            device_info.rank_id = info.serverList[i].devices[j].rankId
            server_info.devices.append(device_info)
        context.server_list.append(server_info)
    return context

cdef message_queue_handle_from_cpp(const CAccelerateMsgQueueHandle &c_handle):
    handle = Handle
    handle.n_reader = c_handle.worldSize
    handle.rank = c_handle.rank
    handle.max_chunk_bytes = c_handle.maxChunkBytes
    handle.max_chunks = c_handle.maxChunks
    handle.name = c_handle.name.decode()
    handle.use_async_loop = c_handle.isAsync
    return handle

cdef invoke_type_from_cpp(const CInvokeType & c_invoke_type):
    invoke_type = InvokeType.CreateInstance
    if c_invoke_type == CInvokeType.CREATE_INSTANCE:
        invoke_type = InvokeType.CreateInstance
    elif c_invoke_type == CInvokeType.INVOKE_MEMBER_FUNCTION:
        invoke_type = InvokeType.InvokeFunction
    elif c_invoke_type == CInvokeType.CREATE_NORMAL_FUNCTION_INSTANCE:
        invoke_type = InvokeType.CreateInstanceStateless
    elif c_invoke_type == CInvokeType.INVOKE_NORMAL_FUNCTION:
        invoke_type = InvokeType.InvokeFunctionStateless
    elif c_invoke_type == CInvokeType.GET_NAMED_INSTANCE_METADATA:
        invoke_type = InvokeType.GetNamedInstanceMeta
    elif c_invoke_type == CInvokeType.DELETE_REMOTE_TENSOR:
        invoke_type = InvokeType.DeleteRemoteTensor
    return invoke_type

cdef parse_rginfo_to_python(cRgInfoUnit: CResourceGroupUnit):
    """parse cpp rginfo into python"""
    cdef:
        CRgInfo c_rg_info
        string c_name
        CBundleInfo c_bundle

    python_resource_groups = {}
    for item in cRgInfoUnit.resourceGroups:
        c_name = item.first
        c_rg_info = item.second
        python_status = CommonStatus(
            code=c_rg_info.status.code,
            message=c_rg_info.status.message.decode()
        )
        python_opt = Option(
            priority=c_rg_info.opt.priority,
            groupPolicy=c_rg_info.opt.groupPolicy,
            extension={
                k.decode(): v.decode()
                for k, v in c_rg_info.opt.extension
            }
        )
        python_bundles = []
        for c_bundle in c_rg_info.bundles:
            python_resources_map = {}
            for resource_item in c_bundle.resources.resources:
                c_res = resource_item.second
                python_resource = Resource(
                    name=c_res.name.decode(),
                    type=Resource.Type(c_res.type),
                    scalar=Resource.Scalar(
                        value=c_res.scalar.value,
                        limit=c_res.scalar.limit
                    )
                )
                python_resources_map[resource_item.first.decode()] = python_resource
            python_resources = Resources(resources=python_resources_map)
            bundle_status = CommonStatus(
                code=c_bundle.status.code,
                message=c_bundle.status.message.decode()
            )
            python_kv_labels = {
                k.decode(): v.decode()
                for k, v in c_bundle.kvLabels
            }
            python_bundle = BundleInfo(
                bundleId=c_bundle.bundleId.decode(),
                rGroupName=c_bundle.rGroupName.decode(),
                parentRGroupName=c_bundle.parentRGroupName.decode(),
                functionProxyId=c_bundle.functionProxyId.decode(),
                functionAgentId=c_bundle.functionAgentId.decode(),
                tenantId=c_bundle.tenantId.decode(),
                resources=python_resources,
                labels=[label.decode() for label in c_bundle.labels],
                status=bundle_status,
                parentId=c_bundle.parentId.decode(),
                kvLabels=python_kv_labels
            )
            python_bundles.append(python_bundle)
        python_rg_info = RgInfo(
            name=c_rg_info.name.decode(),
            owner=c_rg_info.owner.decode(),
            appId=c_rg_info.appId.decode(),
            tenantId=c_rg_info.tenantId.decode(),
            bundles=python_bundles,
            status=python_status,
            parentId=c_rg_info.parentId.decode(),
            requestId=c_rg_info.requestId.decode(),
            traceId=c_rg_info.traceId.decode(),
            opt=python_opt
        )
        python_resource_groups[c_name.decode()] = python_rg_info
    return ResourceGroupUnit(resourceGroups=python_resource_groups)


def load_code_from_datasystem(code_id: str):
    """get code from datasystem"""
    cdef:
        vector[string] c_ids
        pair[CErrorInfo, vector[shared_ptr[CBuffer]]] ret
    cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
    if c_libruntime == nullptr:
        raise RuntimeError("already finalized")
    c_ids.push_back(code_id)
    _logger.debug("code id: %s", code_id)
    with nogil:
        c_libruntime.get().SetTenantIdWithPriority()
        c_libruntime.get().IncreaseReference(c_ids)
        ret = c_libruntime.get().GetBuffers(c_ids, 60000, False)
        c_libruntime.get().DecreaseReference(c_ids)
    if not ret.first.OK():
        raise RuntimeError(
            f"failed to get object, "
            f"code: {ret.first.Code()}, module code {ret.first.MCode()}, msg: {ret.first.Msg().decode()}")
    it = ret.second.begin()
    return yr.serialization.Serialization().deserialize(Buffer.make(dereference(it)))

def load_code_from_bytes(code: bytes):
    """get code from bytes"""
    cdef const char* c_data = code
    cdef shared_ptr[CBuffer] data_buf
    data_buf = dynamic_pointer_cast[CBuffer, CSharedBuffer](make_shared[CSharedBuffer](<void *>c_data, len(code)))
    return yr.serialization.Serialization().deserialize(Buffer.make(data_buf))

def write_to_cbuffer(serialized_object: SerializedObject):
    # This method is for unit test suite 'test_serialization'
    cdef shared_ptr[CBuffer] c_buffer
    cdef int64_t data_size
    data_size = len(serialized_object)
    c_buffer = dynamic_pointer_cast[CBuffer, StringNativeBuffer](make_shared[StringNativeBuffer](data_size))
    buf = Buffer.make(c_buffer)
    serialized_object.write_to(buf)
    return buf

cdef shared_ptr[CBuffer] get_cbuffer(buf: Buffer):
    cdef shared_ptr[CBuffer] c_buffer
    c_buffer = buf.buffer
    return c_buffer

cdef CErrorInfo memory_copy(const shared_ptr[CBuffer] c_buffer, const char * data, uint64_t size) noexcept nogil:
    return c_buffer.get().MemoryCopy(<const void *> data, size)

cdef void memory_copy_string(char[] privateKeyPaaswd, const char * data, uint64_t size) noexcept nogil:
    if (0 < size < 100):
        for i in range(size):
            privateKeyPaaswd[i] = data[i]
    privateKeyPaaswd[size] = 0

cdef CErrorInfo write_str2buffer(const shared_ptr[CBuffer] c_buffer, const char * serialized_object,
                                 unordered_set[string] nest_ids_set) except*:
    cdef:
        CErrorInfo c_error_info

    with nogil:
        c_error_info = c_buffer.get().WriterLatch()
        if not c_error_info.OK():
            return c_error_info

    try:
        c_error_info = memory_copy(c_buffer, serialized_object, len(serialized_object))
        if not c_error_info.OK():
            return c_error_info

        with nogil:
            c_error_info = c_buffer.get().Seal(nest_ids_set)
            if not c_error_info.OK():
                return c_error_info
    finally:
        with nogil:
            c_error_info = c_buffer.get().WriterUnlatch()
            if not c_error_info.OK():
                return c_error_info
    return CErrorInfo()

cdef CErrorInfo write2buffer(const shared_ptr[CBuffer] c_buffer, SerializedObject serialized_object,
                             unordered_set[string] nest_ids_set) except*:
    cdef:
        CErrorInfo c_error_info

    with nogil:
        c_error_info = c_buffer.get().WriterLatch()
        if not c_error_info.OK():
            return c_error_info
    try:
        serialized_object.write_to(Buffer.make(c_buffer))
        with nogil:
            c_error_info = c_buffer.get().Seal(nest_ids_set)
            if not c_error_info.OK():
                return c_error_info
    finally:
        with nogil:
            c_error_info = c_buffer.get().WriterUnlatch()
            if not c_error_info.OK():
                return c_error_info

    return CErrorInfo()

cdef CErrorInfo write2DataObject(const shared_ptr[CDataObject] c_dataObj, SerializedObject serialized_object,
                                 unordered_set[string] nest_ids_set) except*:
    cdef:
        CErrorInfo c_error_info
        shared_ptr[CBuffer] c_buffer


    with nogil:
        c_buffer = c_dataObj.get().buffer
    return write2buffer(c_buffer, serialized_object, nest_ids_set)


def execute_streaming_generator_sync(generator_id, gen):
    index = 0
    try:
        for output in gen:
            notify_generator_result(generator_id, index, output, ErrorInfo())
            index = index + 1
    except Exception as e:
        err = ErrorInfo(ErrorCode.ERR_USER_FUNCTION_EXCEPTION, ModuleCode.RUNTIME,
                                     f"failed to execute user function, err: {str(e)}")
        notify_generator_result(generator_id, index, None, err)
        return
    notify_generator_finished(generator_id, index)


cdef CErrorInfo function_execute_callback_internal(const CFunctionMeta & functionMeta, const CInvokeType invokeType,
                                                   const vector[shared_ptr[CDataObject]] & rawArgs,
                                                   vector[shared_ptr[CDataObject]] & returnObjects) except*:
    cdef:
        shared_ptr[CBuffer] c_buffer
        uint64_t total_native_buffer_size = 0
        CErrorInfo c_error_info
        vector[string] nested_ids
        unordered_set[string] nested_ids_set
        shared_ptr[CInternalWaitResult] ret
        int c_index
        int64_t data_size
        int meta_size
        int nested_len
        int no_timeout = -1
        CFiberEvent genevent
    func_meta = function_meta_from_cpp(functionMeta)
    args = [Buffer.make(rawArgs.at(i).get().buffer) for i in range(rawArgs.size())]
    invoke_type = invoke_type_from_cpp(invokeType)
    return_nums = returnObjects.size()
    if ((invokeType == CInvokeType.CREATE_INSTANCE and func_meta.isAsync) or func_meta.apiType == ApiType.Serve):
        _logger.debug("start initlize _eventloop_for_default_cg")
        global _actor_is_async
        _actor_is_async = True
        global _eventloop_for_default_cg
        _eventloop_for_default_cg = create_new_event_loop()
        global _thread_for_default_cg
        _thread_for_default_cg = threading.Thread(
            target=lambda: _eventloop_for_default_cg.run_forever(),
            name="AsyncIO Thread: default")
        _thread_for_default_cg.start()
    cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
    if c_libruntime == nullptr:
        raise RuntimeError("already finalized")
    result_list = []
    error_info = ErrorInfo()
    cdef:
        CFiberEvent event
    is_async_execute = invokeType in (CInvokeType.INVOKE_MEMBER_FUNCTION, CInvokeType.CREATE_INSTANCE) or func_meta.apiType == ApiType.Serve
    if is_async_execute and _eventloop_for_default_cg is not None:
        async def function_executor():
            try:
                if func_meta.apiType == ApiType.Serve:
                    result_list, error_info = await Executor(func_meta, args, invoke_type, return_nums, _serialization_ctx, True).execute_serve()
                else:
                    result_list, error_info = Executor(func_meta, args, invoke_type, return_nums, _serialization_ctx, True).execute()
                real_result_list = []
                for index, value in enumerate(result_list):
                    if asyncio.iscoroutine(value):
                        res = await value
                        real_result_list.append(res)
                    else:
                        real_result_list.append(value)
                return real_result_list, error_info
            finally:
                event.Notify()

        future = asyncio.run_coroutine_threadsafe(function_executor(), _eventloop_for_default_cg)
        with nogil:
            (c_libruntime.get().WaitEvent(event))

        try:
            result_list, error_info = future.result()
        except concurrent.futures.CancelledError:
            error_info = ErrorInfo(ErrorCode.ERR_USER_FUNCTION_EXCEPTION, ModuleCode.RUNTIME, "exec async func err")
        except Exception as e:
            error_info = ErrorInfo(ErrorCode.ERR_USER_FUNCTION_EXCEPTION, ModuleCode.RUNTIME, "exec async func err")
            result_list = [YRInvokeError(e, traceback.format_exc())]
    else:
        result_list, error_info = Executor(func_meta, args, invoke_type, return_nums, _serialization_ctx, False).execute()
    if error_info.error_code == ErrorCode.ERR_USER_FUNCTION_EXCEPTION and result_list \
            and isinstance(result_list[0], YRInvokeError):
        try:
            serialized_object = _serialization_ctx.serialize(result_list[0])
        except (pickle.PickleError, TypeError, AttributeError) as serialize_err:
            _logger.warning("Failed to serialize YRInvokeError, falling back to string representation: %s",
                            str(serialize_err))
            fallback_err = YRInvokeError(result_list[0].cause, result_list[0].traceback_str)
            fallback_err.cause = RuntimeError(_cause_to_str(result_list[0].cause))
            try:
                serialized_object = _serialization_ctx.serialize(fallback_err)
            except Exception as fallback_err_inner:
                _logger.error("Fallback serialization also failed: %s", str(fallback_err_inner))
                return error_info_from_py(ErrorInfo(ErrorCode.ERR_USER_FUNCTION_EXCEPTION, ModuleCode.RUNTIME,
                                                    "Failed to serialize invocation error"))
        meta_size = constants.METALEN
        data_size = len(serialized_object) - constants.METALEN
        with nogil:
            c_libruntime.get().SetTenantIdWithPriority()
            c_error_info = c_libruntime.get().AllocReturnObject(
                returnObjects.at(0), meta_size, data_size, nested_ids, total_native_buffer_size)
        if not c_error_info.OK():
            return c_error_info
        c_buffer = returnObjects.at(0).get().buffer
        c_error_info = write2buffer(c_buffer, serialized_object, nested_ids_set)
        if not c_error_info.OK():
            return c_error_info
        return error_info_from_py(error_info)
    if error_info.error_code != ErrorCode.ERR_OK:
        return error_info_from_py(error_info)
    need_serialize = False
    if func_meta.apiType == ApiType.Function and \
            invoke_type in (InvokeType.InvokeFunction, InvokeType.InvokeFunctionStateless, InvokeType.GetNamedInstanceMeta, InvokeType.DeleteRemoteTensor):
        need_serialize = True
    if func_meta.isGenerator and invoke_type in (InvokeType.InvokeFunction, InvokeType.InvokeFunctionStateless):
        generator_id = returnObjects.at(0).get().id.decode()
        if len(generator_id) == 0:
            return CErrorInfo(CErrorCode.ERR_INNER_SYSTEM_ERROR, CModuleCode.RUNTIME, "generator_id should not be empty".encode())
        is_async_gen = inspect.isasyncgen(result_list[0])
        is_sync_gen = inspect.isgenerator(result_list[0])
        if (not is_async_gen and not is_sync_gen):
            print("should return a geneator, but get ", type(result_list))
            return CErrorInfo(CErrorCode.ERR_USER_FUNCTION_EXCEPTION, CModuleCode.RUNTIME, "should return a generator".encode())
        if is_sync_gen:
            execute_streaming_generator_sync(generator_id, result_list[0])
        else:
            async def async_generator():
                gen = result_list[0]
                index = 0
                try:
                    async for output in gen:
                        notify_generator_result(generator_id, index, output, ErrorInfo())
                        index = index + 1
                    notify_generator_finished(generator_id, index)
                except Exception as e:
                    err = ErrorInfo(ErrorCode.ERR_USER_FUNCTION_EXCEPTION, ModuleCode.RUNTIME,
                                     f"failed to execute user function, err: {str(e)}")
                    notify_generator_result(generator_id, index, None, err)
                finally:
                    genevent.Notify()
            future = asyncio.run_coroutine_threadsafe(async_generator(), _eventloop_for_default_cg)
            with nogil:
                (CLibruntimeManager.Instance().GetLibRuntime().get().WaitEvent(genevent))
            future.result()
        return CErrorInfo(CErrorCode.ERR_OK, CModuleCode.RUNTIME, "".encode())

    for i in range(return_nums):
        c_index = i
        nested_ids.clear()
        nested_ids_set.clear()
        total_bytes = 0
        if need_serialize:
            serialized_object = _serialization_ctx.serialize(result_list[i])
            total_bytes = len(serialized_object)
            nested_len = len(serialized_object.nested_refs)
            for nested_ref in serialized_object.nested_refs:
                nested_ids.push_back(nested_ref.id)
                nested_ids_set.insert(nested_ref.id)
            if nested_len != 0:
                with nogil:
                    ret = CLibruntimeManager.Instance().GetLibRuntime().get().Wait(nested_ids, nested_len, no_timeout)

                exception_ids = []
                exception_id = ret.get().exceptionIds.begin()
                while exception_id != ret.get().exceptionIds.end():
                    exception_ids.append(
                        f"{dereference(exception_id).first.decode()} "
                        f"code: {dereference(exception_id).second.Code()}, "
                        f"module code: {dereference(exception_id).second.MCode()} "
                        f"message: {dereference(exception_id).second.Msg().decode()}")
                    postincrement(exception_id)
                if len(exception_ids) != 0:
                    return CErrorInfo(CErrorCode.ERR_USER_FUNCTION_EXCEPTION, CModuleCode.RUNTIME, " ".join(exception_ids))
        else:
            serialized_object = result_list[i]
            if serialized_object:
                total_bytes = len(serialized_object)
        if serialized_object is None:
            continue
        meta_size = constants.METALEN
        data_size = total_bytes - constants.METALEN
        with nogil:
            c_libruntime.get().SetTenantIdWithPriority()
            c_error_info = c_libruntime.get().AllocReturnObject(
                returnObjects.at(c_index), meta_size, data_size, nested_ids, total_native_buffer_size)
        if not c_error_info.OK():
            return c_error_info
        c_buffer = returnObjects.at(i).get().buffer
        if need_serialize:
            c_error_info = write2buffer(c_buffer, serialized_object, nested_ids_set)
        else:
            c_error_info = write_str2buffer(c_buffer, serialized_object, nested_ids_set)
    return c_error_info


cdef CErrorInfo accelerate_execute_callback_internal(const CAccelerateMsgQueueHandle & input_handle, CAccelerateMsgQueueHandle & return_handle) except*:
    cdef CErrorInfo ret
    rpc_broadcast_mq = MessageQueue.create_from_handle(message_queue_handle_from_cpp(input_handle))
    fcc_max_chunk_bytes = int(os.environ.get("FCC_MAX_CHUNK_BYTES", 1024 * 1024 * 10))
    fcc_max_chunks = int(os.environ.get("FCC_MAX_CHUNKS", 10))
    worker_response_mq = MessageQueue(1, fcc_max_chunk_bytes, fcc_max_chunks)
    return_handle = message_queue_handle_from_py(worker_response_mq.export_handle())
    ACCELERATE_WORKER = Worker(rpc_broadcast_mq, worker_response_mq, input_handle.isAsync)
    ACCELERATE_WORKER.start()
    return ret

cdef CErrorInfo accelerate_execute_callback(const CAccelerateMsgQueueHandle & input_handle, CAccelerateMsgQueueHandle & return_handle) noexcept nogil:
    with gil:
        try:
            return accelerate_execute_callback_internal(input_handle, return_handle)
        except Exception as e:
            _logger.debug(str(e))
            return CErrorInfo(CErrorCode.ERR_INNER_SYSTEM_ERROR, CModuleCode.RUNTIME, str(e))

cdef CErrorInfo function_execute_callback(const CFunctionMeta & functionMeta, const CInvokeType invokeType,
                                          const vector[shared_ptr[CDataObject]] & rawArgs,
                                          vector[shared_ptr[CDataObject]] & returnObjects) noexcept nogil:
    with gil:
        try:
            return function_execute_callback_internal(functionMeta, invokeType, rawArgs, returnObjects)
        except Exception as e:
            _logger.exception(e)
            return CErrorInfo(CErrorCode.ERR_INNER_SYSTEM_ERROR, CModuleCode.RUNTIME, str(e))

cdef CErrorInfo load_function_callback(const vector[string] & codePath) noexcept nogil:
    cdef CErrorInfo errorInfo
    with gil:
        code_paths = [codePath.at(i).decode() for i in range(codePath.size())]
        error_info = yr.code_manager.CodeManager().load_functions(code_paths)
        errorInfo = error_info_from_py(error_info)
        return errorInfo

cdef CErrorInfo shutdown_function_callback(gracePeriodSecond: uint64_t) noexcept nogil:
    with gil:
        _logger.debug("Start to execute graceful exit.")
        error_info = Executor.shutdown(gracePeriodSecond)
        _logger.info("Execution of graceful exit finished.")
        return error_info_from_py(error_info)

cdef CErrorInfo prepare_snap_callback() noexcept nogil:
    with gil:
        _logger.debug("Start to execute prepare snapshot.")
        error_info = Executor.before_snapshot()
        _logger.info("Execution of prepare snapshot finished.")
        return error_info_from_py(error_info)

cdef CErrorInfo snap_started_callback() noexcept nogil:
    with gil:
        _logger.debug("Start to execute snap started.")
        error_info = Executor.after_snapstart()
        _logger.info("Execution of snap started finished.")
        return error_info_from_py(error_info)

cdef void refresh_env_callback() noexcept nogil:
    with gil:
        _logger.debug("Start to refresh environment variables.")
        try:
            refresh_env()
            _logger.info("Environment variables refreshed after snapshot restore")
        except Exception as e:
            _logger.error(f"Failed to refresh environment variables: {e}")

cdef CErrorInfo build_invoke_arg(arg, vector[CInvokeArg]& invokeArgs, string tenantId):
    cdef:
        CInvokeArg c_arg
        shared_ptr[CBuffer] data_buf
        CErrorInfo c_error_info
        cdef int64_t data_size
    c_arg.dataObj = make_shared[CDataObject]()
    if arg.serialized_obj is not None and isinstance(arg.serialized_obj, SerializedObject):
        data_buf = get_cbuffer(write_to_cbuffer(arg.serialized_obj))
    elif arg.buf is not None:
        data_buf = dynamic_pointer_cast[CBuffer, StringNativeBuffer](make_shared[StringNativeBuffer](len(arg.buf)))
        c_arg.dataObj.get().SetBuffer(data_buf)
        if len(arg.buf) != 0:
            c_error_info = memory_copy(data_buf, arg.buf, len(arg.buf))
            if not c_error_info.OK():
                raise RuntimeError(
                    f"failed to build invoke args, "
                    f"code: {c_error_info.Code()}, module code {c_error_info.MCode()}, msg: {c_error_info.Msg().decode()}")
    c_arg.dataObj.get().SetBuffer(data_buf)
    c_arg.isRef = arg.is_ref
    c_arg.objId = arg.obj_id
    c_arg.tenantId = tenantId
    for obj in arg.nested_objects:
        c_arg.nestedObjects.insert(obj)
    invokeArgs.push_back(move(c_arg))

cdef vector[CInvokeArg] parse_invoke_args(args, vector[CInvokeArg]& invokeArgs, string tenantId):
    for arg in args:
        build_invoke_arg(arg, invokeArgs, tenantId)

def get_conda_bin_executable(executable_name: str) -> str:
    conda_home = os.environ.get("YR_CONDA_HOME")
    if conda_home:
        return conda_home
    else:
        raise ValueError(
            "please configure YR_CONDA_HOME environment variable which contain a bin subdirectory"
        )

cdef parse_invoke_opts(CInvokeOptions & opts, opt: yr.InvokeOptions, group_info: GroupInfo = None):
    cdef:
        string concurrency_key = "Concurrency".encode()
        shared_ptr[CAffinity] c_affinity
    create_opt = runtime_env.parse_runtime_env(opt)
    if runtime_env.WORKING_DIR_KEY in create_opt:
        opts.workingDir = create_opt.pop(runtime_env.WORKING_DIR_KEY)
    runtime_env_vars = create_opt.pop("env_vars", {})
    merged_env_vars = {}
    for key, value in runtime_env_vars.items():
        merged_env_vars[key] = value
    for key, value in opt.env_vars.items():
        merged_env_vars[key] = value
    for key, value in merged_env_vars.items():
        opts.envVars.insert(pair[string, string](key, value))
    for key, value in create_opt.items():
        opts.createOptions.insert(pair[string, string](key, value))
    # port forwarding: serialize to createOptions["network"] JSON
    pf_opt = port_forwarding.parse_port_forwardings(opt)
    for key, value in pf_opt.items():
        opts.createOptions.insert(pair[string, string](key, value))
    opts.cpu = opt.cpu
    opts.memory = opt.memory
    opts.cpuLimit = opt.cpu_limit
    opts.memoryLimit = opt.mem_limit
    # Only set concurrency if explicitly provided (not None)
    if opt.concurrency is not None:
        opts.customExtensions.insert(pair[string, string](concurrency_key, str(opt.concurrency)))
    for key, value in opt.custom_resources.items():
        opts.customResources.insert(pair[string, float](key, value))
    for key, value in opt.custom_extensions.items():
        opts.customExtensions.insert(pair[string, string](key, value))
    for key, value in opt.pod_labels.items():
        opts.podLabels.insert(pair[string, string](key, value))
    for arg in opt.labels:
        opts.labels.push_back(arg)
    for key, value in opt.affinity.items():
        opts.affinity.insert(pair[string, string](key, value))
    for key, value in opt.alias_params.items():
        opts.aliasParams.insert(pair[string, string](key, value))
    opts.retryTimes = opt.retry_times
    opts.device = CDevice()
    opts.device.name = opt.device.name
    opts.maxInvokeLatency = opt.max_invoke_latency
    opts.minInstances = opt.min_instances
    opts.maxInstances = opt.max_instances
    opts.isDataAffinity = opt.is_data_affinity
    opts.resourceGroupOpts = resource_group_options_from_py(opt.resource_group_options)
    opts.groupName = opt.group_name.encode()
    if group_info is not None:
        opts.functionGroupOpts = function_group_options_from_py(opt.function_group_options, group_info.group_size)
        opts.groupName = group_info.group_name.encode()
    for affinity in opt.schedule_affinities:
        c_affinity = affinity_from_py_to_cpp(affinity, opt.preferred_priority, opt.required_priority,
                                             opt.preferred_anti_other_labels)
        if c_affinity == nullptr:
            raise ValueError("Failed to convert affinity to cpp affinity.")
        opts.scheduleAffinities.push_back(c_affinity)
    opts.recoverRetryTimes = opt.recover_retry_times
    if opt.need_order:
        opts.needOrder = True
    else:
        opts.needOrder = False
    opts.traceId = opt.trace_id
    opts.preemptedAllowed = opt.preempted_allowed
    opts.instancePriority = opt.instance_priority
    opts.scheduleTimeoutMs = opt.schedule_timeout_ms
    opts.isDeleteRemoteTensor = opt.is_delete_remote_tensor
    opts.debug.enable = opt.debug.enable
    opts.bypassDatasystem = opt.bypass_datasystem

cdef class Producer:
    """
    Producer interface class.

    Examples:
        >>> try:
        ...     producer_config = ProducerConfig(
        ...         delay_flush_time=5,
        ...         auto_clean_up=True,
        ...     )
        ...     producer = yr.create_stream_producer("streamName", producer_config)
        ...     # .......
        ...     data = b"hello"
        ...     element = yr.Element(data=data, id=0)
        ...     producer.send(element)
        ...     producer.flush()
        ...     producer.close()
        ... except RuntimeError as exp:
        ...     # .......
        ...     pass
    """
    cdef:
        shared_ptr[CStreamProducer] producer

    @staticmethod
    cdef make(shared_ptr[CStreamProducer] producer):
        self = Producer()
        self.producer = producer
        return self

    def __init__(self):
        """
        Initialize a Producer instance.
        """
        pass

    def send(self, element: Element, timeout_ms: int = None) -> None:
        """
        The Producer sends data, which is first placed into a buffer.
        The buffer is then flushed either according to the configured automatic flush strategy
        (after a certain interval or when the buffer is full),
        or by manually invoking the flush operation to make the data accessible to the consumer.

        Args:
            element (Element): The Element data to be sent.
            timeout_ms (int, optional): The timeout in milliseconds. Defaults to ``None``.

        Raises:
            RuntimeError: If the send operation fails.
        """
        cdef:
            CElement e = CElement(element.data, len(element.data), element.id)
            CErrorInfo ret
            int c_timeout_ms
        if timeout_ms == None:
            with nogil:
                ret = self.producer.get().Send(e)
        else:
            c_timeout_ms = timeout_ms
            with nogil:
                ret = self.producer.get().Send(e, c_timeout_ms)
        if not ret.OK():
            raise RuntimeError(
                f"failed to send, "
                f"code: {ret.Code()}, module code {ret.MCode()}, msg: {ret.Msg().decode()}")

    def close(self) -> None:
        """
        Closing the producer will trigger an automatic flush of the data buffer and
        indicate that the data buffer is no longer in use. Once closed, the producer cannot be used again.
        """
        cdef CErrorInfo ret
        ret = self.producer.get().Close()
        if not ret.OK():
            raise RuntimeError(
                f"failed to close, "
                f"code: {ret.Code()}, module code {ret.MCode()}, msg: {ret.Msg().decode()}")

cdef class SharedBuffer:
    cdef:
        shared_ptr[CBuffer] c_buffer
    buf: memoryview
    @staticmethod
    cdef make(shared_ptr[CBuffer] c_buffer):
        self = SharedBuffer()
        self.c_buffer = c_buffer
        self.buf = memoryview(Buffer.make(c_buffer))
        return self
    def get_buf(self) -> memoryview:
        return self.buf

    def set_buf(self, buf: memoryview):
        self.buf = buf

cdef class Consumer:
    """
    Consumer interface class.

    Examples:
        >>> try:
        ...     config = yr.SubscriptionConfig("subName", yr.SubscriptionConfig.subscriptionType.STREAM)
        ...     consumer = yr.create_stream_consumer("streamName", config)
        ...     # .......
        ...     elements = consumer.receive(6000, 1)
        ... except RuntimeError as exp:
        ...     # .......
        ...     pass
    """
    cdef:
        shared_ptr[CStreamConsumer] consumer

    @staticmethod
    cdef make(shared_ptr[CStreamConsumer] consumer):
        self = Consumer()
        self.consumer = consumer
        return self

    def receive(self, timeout_ms: int, expect_num: int = None) -> List[Element]:
        """
        Consumer receives data with subscription support.
        The call waits until either the expected number of elements `expect_num` is received
        or the timeout `timeout_ms` is reached.

        Args:
            timeout_ms (int): Timeout in milliseconds.
            expect_num (int, optional): Expected number of elements to receive.

        Raises:
            RuntimeError: If receiving data fails.

        Return:
            The actual list of received elements.
            Data Type is List[Element].
        """
        cdef:
            vector[CElement] out_elements
            CErrorInfo ret
            int c_expect_num
            int c_timeout_ms = timeout_ms
        result = []
        if expect_num:
            c_expect_num = expect_num
            with nogil:
                ret = self.consumer.get().Receive(c_expect_num, c_timeout_ms, out_elements)
        else:
            with nogil:
                ret = self.consumer.get().Receive(c_timeout_ms, out_elements)
        if not ret.OK():
            raise RuntimeError(
                f"failed to receive, "
                f"code: {ret.Code()}, module code {ret.MCode()}, msg: {ret.Msg().decode()}")
        it = out_elements.begin()
        while it != out_elements.end():
            result.append(Element(
                PyBytes_FromStringAndSize(<const char *> dereference(it).ptr, dereference(it).size),
                dereference(it).id))
            postincrement(it)
        return result

    def ack(self, element_id: int) -> None:
        """
        After the consumer finishes using the element identified by `element_id`,
        it must acknowledge (ack) the element. This allows all workers to determine
        whether all consumers have finished processing the data. Once a page has been
        fully consumed, internal memory reclamation may be triggered.

        Args:
            element_id (int): The ID of the element to acknowledge.

        Raises:
             RuntimeError: If acknowledging the element fails.

        Return:
            None.

        """
        cdef CErrorInfo ret
        ret = self.consumer.get().Ack(element_id)
        if not ret.OK():
            raise RuntimeError(
                f"failed to ack, "
                f"code: {ret.Code()}, module code {ret.MCode()}, msg: {ret.Msg().decode()}")

    def close(self):
        """
        Turning off consumer will automatically trigger Ack.

        Raises:
            RuntimeError: If failed to close.
        """
        cdef CErrorInfo ret
        ret = self.consumer.get().Close()
        if not ret.OK():
            raise RuntimeError(
                f"failed to close, "
                f"code: {ret.Code()}, module code {ret.MCode()}, msg: {ret.Msg().decode()}")

cdef CErrorInfo dump_instance(const string & checkpointId, shared_ptr[CBuffer] & data) noexcept with gil:
    cdef:
        shared_ptr[CBuffer] c_buffer
        int64_t data_size
        SerializedObject serialized_inst
    _logger.debug("Starts to serialze the instance for checkpoint, instance ID: %s", checkpointId.decode())
    try:
        serialized_inst = _serialization_ctx.serialize(InstanceManager().get_instance_package())
    except Exception as e:
        print(f'failed to dump instance {str(e)}')
        return CErrorInfo(CErrorCode.ERR_INNER_SYSTEM_ERROR, CModuleCode.RUNTIME, str(e))
    data_size = len(serialized_inst)
    c_buffer = dynamic_pointer_cast[CBuffer, NativeBuffer](make_shared[NativeBuffer](data_size))
    py_buffer = Buffer.make(c_buffer)
    serialized_inst.write_to(py_buffer)
    data.swap(c_buffer)
    _logger.debug("Succeeded to serialze the instance for checkpoint, instance ID: %s", checkpointId.decode())
    return CErrorInfo()

cdef CErrorInfo load_instance(shared_ptr[CBuffer] data) noexcept with gil:
    _logger.debug("Starts to deserialze the instance buffer for recover")
    py_buffer = Buffer.make(data)
    try:
        InstanceManager().init_from_inspackage(_serialization_ctx.deserialize(py_buffer))
        if InstanceManager().is_async and _eventloop_for_default_cg is None:
            _logger.debug("instance is async, reinitlize _eventloop_for_default_cg")
            global _actor_is_async
            _actor_is_async = True
            global _eventloop_for_default_cg
            _eventloop_for_default_cg = asyncio.new_event_loop()
            global _thread_for_default_cg
            _thread_for_default_cg = threading.Thread(
                target=lambda: _eventloop_for_default_cg.run_forever(),
                name="AsyncIO Thread: default")
            _thread_for_default_cg.start()
    except Exception as e:
        print(f'failed to load instance {str(e)}')
        return CErrorInfo(CErrorCode.ERR_INNER_SYSTEM_ERROR, CModuleCode.RUNTIME, str(e))
    _logger.info("Succeeded to deserialze the instance buffer for recover")
    return CErrorInfo()

cdef void async_callback(shared_ptr[CDataObject] data, const CErrorInfo & error, void *user_callback_ptr) noexcept with gil:
    err =  error_info_from_cpp(error)
    try:
        user_callback = <object>user_callback_ptr
        buf = Buffer.make(data.get().buffer)
        user_callback(data.get().id, err, buf)
    except Exception as e:
        print(f"failed to run async callback (user func) {e}")
    finally:
        cpython.Py_DECREF(user_callback)

cdef pair[CErrorInfo, shared_ptr[CBuffer]] handle_return_object_callback(shared_ptr[CBuffer] buffer, int rank, string & objId) noexcept with gil:
    cdef:
        CErrorInfo c_error_info
        string c_exception
        uint64_t total_native_buffer_size = 0
        shared_ptr[CBuffer] c_buffer
        unordered_set[string] nested_ids_set
    buf = memoryview(Buffer.make(buffer))
    status, (task_id, result) = decode(buf[2:])
    obj_id = task_id + "_" + str(rank)
    objId = obj_id.encode()
    if status == ResponseStatus.SUCCESS:
        serialized_object = _serialization_ctx.serialize(result)
        total_native_buffer_size = len(serialized_object)
        c_buffer = dynamic_pointer_cast[CBuffer, NativeBuffer](make_shared[NativeBuffer](total_native_buffer_size))
        c_error_info = write2buffer(c_buffer, serialized_object, nested_ids_set)
    elif status == ResponseStatus.FAILURE:
        c_exception = result.encode()
        c_error_info = CErrorInfo(CErrorCode.ERR_USER_FUNCTION_EXCEPTION, CModuleCode.RUNTIME, c_exception)
    return pair[CErrorInfo, shared_ptr[CBuffer]](c_error_info, c_buffer)


cdef CErrorInfo check_signals() noexcept nogil:
    cdef:
        string errmsg
    with gil:
        try:
            PyErr_CheckSignals()
        except KeyboardInterrupt:
            errmsg = "recieve teminal kill signal".encode()
            return CErrorInfo(CErrorCode.ERR_CLIENT_TERMINAL_KILLED, CModuleCode.RUNTIME, errmsg)
    return CErrorInfo()


cdef object session_wait_bridge(str session_id, int64_t timeout_ms):
    cdef:
        string c_session_id = session_id.encode()
        pair[CErrorInfo, shared_ptr[CBuffer]] ret
        shared_ptr[CBuffer] result_buffer
        CErrorInfo err
    cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
    if c_libruntime == nullptr:
        raise RuntimeError("already finalized")
    with nogil:
        c_libruntime.get().SetTenantIdWithPriority()
        ret = c_libruntime.get().SessionWait(c_session_id, timeout_ms)
    err = ret.first
    result_buffer = ret.second
    if err.Code() == CErrorCode.ERR_SESSION_TIMEOUT:
        return None
    if err.Code() == CErrorCode.ERR_SESSION_INTERRUPTED:
        raise RuntimeError(
            f"Session wait interrupted: {err.Msg().decode()}")
    if not err.OK():
        raise RuntimeError(
            f"Session wait failed: code: {err.Code()}, module code: {err.MCode()}, msg: {err.Msg().decode()}")
    if result_buffer == nullptr or result_buffer.get().GetSize() == 0:
        return None
    return PyBytes_FromStringAndSize(
        <const char*>result_buffer.get().ImmutableData(),
        <Py_ssize_t>result_buffer.get().GetSize())


cdef void session_notify_bridge(str session_id, bytes data) except *:
    cdef:
        string c_session_id = session_id.encode()
        shared_ptr[CBuffer] c_buffer
        CErrorInfo ret
        Py_ssize_t n = len(data)
    cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
    if c_libruntime == nullptr:
        raise RuntimeError("already finalized")
    c_buffer = dynamic_pointer_cast[CBuffer, NativeBuffer](make_shared[NativeBuffer](<uint64_t>n))
    ret = memory_copy(c_buffer, PyBytes_AS_STRING(data), <uint64_t>n)
    if not ret.OK():
        raise RuntimeError(
            f"failed to prepare session_notify buffer, "
            f"code: {ret.Code()}, module code: {ret.MCode()}, msg: {ret.Msg().decode()}")
    with nogil:
        c_libruntime.get().SetTenantIdWithPriority()
        ret = c_libruntime.get().SessionNotify(c_session_id, c_buffer)
    if not ret.OK():
        raise RuntimeError(
            f"failed to session_notify, "
            f"code: {ret.Code()}, module code: {ret.MCode()}, msg: {ret.Msg().decode()}")

cdef class Fnruntime:
    def __cinit__(self, functionSystemIpAddr, functionSystemPort, functionSystemRtServerIpAddr,
                  functionSystemRtServerPort):
        cdef CLibruntimeConfig config = CLibruntimeConfig()
        cdef CErrorInfo ret
        config.libruntimeOptions.functionExecuteCallback = function_execute_callback
        config.libruntimeOptions.loadFunctionCallback = load_function_callback
        config.libruntimeOptions.shutdownCallback = shutdown_function_callback
        config.libruntimeOptions.checkpointCallback = dump_instance
        config.libruntimeOptions.recoverCallback = load_instance
        config.libruntimeOptions.prepareSnapCallback = prepare_snap_callback
        config.libruntimeOptions.snapStartedCallback = snap_started_callback
        config.libruntimeOptions.refreshEnvCallback = refresh_env_callback
        config.libruntimeOptions.accelerateCallback = accelerate_execute_callback
        config.functionSystemIpAddr = functionSystemIpAddr
        config.functionSystemPort = functionSystemPort
        config.functionSystemRtServerIpAddr = functionSystemRtServerIpAddr
        config.functionSystemRtServerPort = functionSystemRtServerPort
        if ConfigManager().in_cluster:
            config.dataSystemIpAddr = ConfigManager().ds_address.split(":")[0]
            config.dataSystemPort = int(ConfigManager().ds_address.split(":")[1])
        config.metaConfig = ConfigManager().meta_config.to_json()
        config.isDriver = ConfigManager().is_driver
        config.jobId = ConfigManager().job_id
        config.runtimeId = ConfigManager().runtime_id
        if ConfigManager().is_driver:
            config.instanceId = f"driver-{ConfigManager().job_id}".encode()
        config.functionIds.insert(pair[CLanguageType, string](CLanguageType.LANGUAGE_PYTHON,
                                                              ConfigManager().meta_config.functionID.python))
        config.functionIds.insert(pair[CLanguageType, string](CLanguageType.LANGUAGE_CPP,
                                                              ConfigManager().meta_config.functionID.cpp))
        config.functionIds.insert(pair[CLanguageType, string](CLanguageType.LANGUAGE_JAVA,
                                                              ConfigManager().meta_config.functionID.java))
        config.logLevel = ConfigManager().log_level
        config.logDir = ConfigManager().log_dir
        config.logFileSizeMax = ConfigManager().log_file_size_max
        config.logFileNumMax = ConfigManager().log_file_num_max
        config.logFlushInterval = ConfigManager().log_flush_interval
        config.recycleTime = ConfigManager().meta_config.recycleTime
        config.maxTaskInstanceNum = ConfigManager().meta_config.maxTaskInstanceNum
        config.maxConcurrencyCreateNum = ConfigManager().meta_config.maxConcurrencyCreateNum
        config.enableMetrics = ConfigManager().meta_config.enableMetrics
        config.functionMasters = ConfigManager().meta_config.functionMasters
        config.selfLanguage = CLanguageType.LANGUAGE_PYTHON
        config.loadPaths = ConfigManager().load_paths
        config.rpcTimeout = ConfigManager().rpc_timeout
        config.tenantId = ConfigManager().tenant_id
        config.enableMTLS = ConfigManager().enable_mtls
        config.enableTLS = ConfigManager().enable_tls
        config.privateKeyPath = ConfigManager().private_key_path
        config.certificateFilePath = ConfigManager().certificate_file_path
        config.verifyFilePath = ConfigManager().verify_file_path
        memory_copy_string(config.privateKeyPaaswd, ConfigManager().private_key_paaswd,
                           len(ConfigManager().private_key_paaswd))
        config.httpIocThreadsNum = ConfigManager().http_ioc_threads_num
        config.serverName = ConfigManager().server_name
        config.inCluster = ConfigManager().in_cluster
        config.ns = ConfigManager().ns
        config.checkSignals_ = check_signals
        config.workingDir = ConfigManager().working_dir
        config.runtimePublicKeyPath = ConfigManager().runtime_public_key_path
        config.runtimePrivateKeyPath = ConfigManager().runtime_private_key_path
        config.dsPublicKeyPath = ConfigManager().ds_public_key_path
        config.encryptEnable = ConfigManager().enable_ds_encrypt
        config.ns = ConfigManager().ns
        config.logToDriver = ConfigManager().log_to_driver
        config.dedupLogs = ConfigManager().dedup_logs
        config.envFile = ConfigManager().env_file
        config.authToken = ConfigManager().auth_token
        for key, value in ConfigManager().custom_envs.items():
            config.customEnvs.insert(pair[string, string](key, value))
        with nogil:
            ret = CLibruntimeManager.Instance().Init(config)
        if not ret.OK():
            raise ValueError(
                f"failed to init, "
                f"code: {ret.Code()}, module code {ret.MCode()}, msg: {ret.Msg().decode()}")

    def init(self, ctx):
        global _serialization_ctx
        _serialization_ctx = ctx
        yr.code_manager.CodeManager().register_load_code_from_datasystem_func(load_code_from_datasystem)
        yr.code_manager.CodeManager().register_load_code_from_bytes_func(load_code_from_bytes)

    def receive_request_loop(self):
        with nogil:
            CLibruntimeManager.Instance().ReceiveRequestLoop()

    def need_reinit(self):
        cdef bool result
        with nogil:
            result = CLibruntimeManager.Instance().NeedReInit()
        return result

    def reinit(self):
        with nogil:
            CLibruntimeManager.Instance().ReInit()

    def finalize(self):
        with nogil:
            CLibruntimeManager.Instance().Finalize()

    def put(self, serialized_object: SerializedObject, create_param: CreateParam):
        """
        Put data to ds
        :param data: serialized object data
        :param nested_object_ids: nested object in data
        :param create_param create param to datasystem
        :return: object id
        """
        cdef:
            CCreateParam param
            shared_ptr[CDataObject] c_dataObj
            vector[string] nested_ids
            unordered_set[string] nested_ids_set
            pair[CErrorInfo, string] ret
            int64_t data_size
            int64_t meta_size

        param = create_param_from_py(create_param)
        for nested_ref in serialized_object.nested_refs:
            nested_ids.push_back(nested_ref.id)
            nested_ids_set.insert(nested_ref.id)
        meta_size = constants.METALEN
        data_size = len(serialized_object) - constants.METALEN
        c_dataObj = make_shared[CDataObject]()
        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")
        with nogil:
            c_libruntime.get().SetTenantIdWithPriority()
            ret = c_libruntime.get().CreateDataObject(meta_size, data_size, c_dataObj,
                                                                                       nested_ids, param)

        if not ret.first.OK():
            raise RuntimeError(
                f"failed to put object, "
                f"code: {ret.first.Code()}, module code {ret.first.MCode()}, msg: {ret.first.Msg().decode()}")

        c_error_info = write2DataObject(c_dataObj, serialized_object, nested_ids_set)

        if not c_error_info.OK():
            raise RuntimeError(
                f"failed to put object, "
                f"code: {c_error_info.Code()}, module code {c_error_info.MCode()}, msg: {c_error_info.Msg().decode()}")
        return ret.second.decode("utf-8")

    def get(self, ids: List[str], timeout_ms: int, allow_partial: bool) -> List[Buffer]:
        """
        Get data from ds
        :param ids: ids which need to get
        :param timeout_ms: timeout
        :param allow_partial: allow partial
        :return: data which get from ds
        """
        cdef:
            vector[string] c_ids
            pair[CErrorInfo, vector[shared_ptr[CDataObject]]] ret
            int c_timeout_ms = timeout_ms
            shared_ptr[CDataObject] c_dataObj
            shared_ptr[CBuffer] c_buffer
            vector[CStackTraceInfo] c_stack_trace_info
        for i in ids:
            c_ids.push_back(i)
        c_dataObj = make_shared[CDataObject]()
        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")
        with nogil:
            c_libruntime.get().SetTenantIdWithPriority()
            ret = c_libruntime.get().GetDataObjects(c_ids, c_timeout_ms, allow_partial)
        result = []
        if not ret.first.OK():
            if error_code_from_cpp(ret.first.Code()) == ErrorCode.ERR_GENERATOR_FINISHED:
                raise GeneratorEndError(
                    f"gernerator stop, "
                    f"code: {ret.first.Code()}, module code {ret.first.MCode()}, msg: {ret.first.Msg().decode()}")
            if ret.first.Code() == CErrorCode.ERR_USER_FUNCTION_EXCEPTION or \
                    ret.first.Code() == CErrorCode.ERR_DEPENDENCY_FAILED:
                c_stack_trace_info = ret.first.GetStackTraceInfos()
                it_sti = c_stack_trace_info.begin()
                while it_sti != c_stack_trace_info.end():
                    if dereference(it_sti).Type().decode() == "YRInvokeError":
                        c_buffer = dynamic_pointer_cast[CBuffer, NativeBuffer](
                            make_shared[NativeBuffer](dereference(it_sti).Message().size()))
                        memory_copy(c_buffer, dereference(it_sti).Message().data(),
                                    dereference(it_sti).Message().size())
                        result.append(Buffer.make(c_buffer))
                        return result
                    postincrement(it_sti)
            mesg = ("failed to get object, "
                    f"code: {ret.first.Code()}, module code: {ret.first.MCode()}, message: {ret.first.Msg().decode()}")
            if ret.first.IsTimeout():
                raise TimeoutError(mesg)
            raise RuntimeError(mesg)

        result = []
        for it in ret.second:
            if it == NULL or dereference(it).buffer == NULL:
                result.append(None)
            else:
                result.append(Buffer.make(dereference(it).buffer))
        return result

    def wait(self, objs: List[str], wait_num: int, timeout: int) -> Tuple[List[str], List[str], List[str]]:
        """
        wait objects
        :param objs: objs which need to wait
        :param wait_num: wait number
        :param timeout: timeout
        :return: ready objects, unready objects, exception of objects
        """
        cdef:
            vector[string] c_ids
            shared_ptr[CInternalWaitResult] ret
            int cwaitNum = wait_num
            int ctimeout = timeout
        for i in objs:
            c_ids.push_back(i)
        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")
        with nogil:
            c_libruntime.get().SetTenantIdWithPriority()
            ret = c_libruntime.get().Wait(c_ids, cwaitNum, ctimeout)
        ready_ids = []
        ready_id = ret.get().readyIds.begin()
        while ready_id != ret.get().readyIds.end():
            ready_ids.append(dereference(ready_id).decode())
            postincrement(ready_id)
        unready_ids = []
        unready_id = ret.get().unreadyIds.begin()
        while unready_id != ret.get().unreadyIds.end():
            unready_ids.append(dereference(unready_id).decode())
            postincrement(unready_id)
        exception_ids = []
        exception_id = ret.get().exceptionIds.begin()
        while exception_id != ret.get().exceptionIds.end():
            exception_ids.append(f"{dereference(exception_id).first.decode()}")
            postincrement(exception_id)
        if len(exception_ids) != 0:
            _logger.debug("Gets exception IDs while waiting: %s", exception_ids)
        return ready_ids, unready_ids, exception_ids

    def get_async(self, object_id: str, callback: Callable):
        """
        get async
        :param object_id: object id
        :param callback: user callback
        :return: None
        """
        cpython.Py_INCREF(callback)
        cdef:
            c_object_id = object_id.encode()

        CLibruntimeManager.Instance().GetLibRuntime().get().GetAsync(c_object_id, async_callback, <void*>callback)

    def kv_write(self, key: str, value: bytes, set_param: SetParam) -> None:
        """
        store value to ds
        :param key: key
        :param value: value
        :param set_param: set param
        :return: None
        """
        cdef:
            CSetParam param
            shared_ptr[CBuffer] c_buffer
            CErrorInfo ret
            string c_str = key.encode()

        param = set_param_from_py(set_param)
        c_buffer = dynamic_pointer_cast[CBuffer, NativeBuffer](make_shared[NativeBuffer](len(value)))
        ret = memory_copy(c_buffer, value, len(value))
        if not ret.OK():
            raise RuntimeError(
                f"failed to kv_write, "
                f"code: {ret.Code()}, module code {ret.MCode()}, msg: {ret.Msg().decode()}")
        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")
        with nogil:
            c_libruntime.get().SetTenantIdWithPriority()
            ret = c_libruntime.get().KVWrite(c_str, c_buffer, param)
        if not ret.OK():
            raise RuntimeError(
                f"failed to kv_write, "
                f"code: {ret.Code()}, module code {ret.MCode()}, msg: {ret.Msg().decode()}")

    def kv_m_write_tx(self, keys: List[str], values: List[bytes], m_set_param: MSetParam) -> None:
        """
        Deprecated. Retained only for compatibility with legacy batch write APIs.
        Do not use it in new code.

        store multiple key-value pairs to ds
        :param keys: the keys to set
        :param values: the values to set. Size of values should equal to size of keys.
        :param m_set_param: MSetParams for datasystem stateClient.
        :return: None
        """
        cdef:
            CMSetParam param
            vector[string] c_ids
            vector[shared_ptr[CBuffer]] c_buffers
            CErrorInfo ret

        param = m_set_param_from_py(m_set_param)
        for k_id in keys:
            c_ids.push_back(k_id)

        for value in values:
            c_buffers.push_back(dynamic_pointer_cast[CBuffer, NativeBuffer](make_shared[NativeBuffer](len(value))))
            ret = memory_copy(c_buffers.back(), value, len(value))
            if not ret.OK():
                raise RuntimeError(
                    f"failed to kv_m_write_tx, "
                    f"code: {ret.Code()}, module code {ret.MCode()}, msg: {ret.Msg().decode()}")
        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")
        with nogil:
            c_libruntime.get().SetTenantIdWithPriority()
            ret = c_libruntime.get().KVMSetTx(c_ids, c_buffers, param)
        if not ret.OK():
            raise RuntimeError(
                f"failed to kv_m_write_tx, "
                f"code: {ret.Code()}, module code {ret.MCode()}, msg: {ret.Msg().decode()}")

    def kv_read(self, key: Union[str, List[str]], timeout_ms: int, allow_partial: bool = False) -> List[memoryview]:
        """
        read value from ds
        :param key: key
        :param timeout_ms: timeout
        :param allow_partial: allow_partial
        :return: value
        """
        cdef:
            vector[string] c_ids
            int c_timeout_ms = timeout_ms
            CMultipleReadResult ret
        if isinstance(key, str):
            c_ids.push_back(key)
        else:
            for k_id in key:
                c_ids.push_back(k_id)
        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")
        with nogil:
            c_libruntime.get().SetTenantIdWithPriority()
            ret = c_libruntime.get().KVRead(c_ids, c_timeout_ms, allow_partial)
        if not ret.second.OK():
            raise RuntimeError(
                f"failed to kv_read, "
                f"code: {ret.second.Code()}, module code {ret.second.MCode()}, msg: {ret.second.Msg().decode()}")
        it = ret.first.begin()
        result = []
        while it != ret.first.end():
            result.append(memoryview(Buffer.make(dereference(it))))
            postincrement(it)
        return result

    def kv_get_with_param(self, keys: List[str], get_params: GetParams, timeout_ms: int) -> List[memoryview]:
        """
        read value from ds
        :param key: key
        :param get_params: get params for datasystem
        :param timeout_ms: timeout
        :return: value
        """
        cdef:
            vector[string] c_ids
            CGetParams c_get_params
            int c_timeout_ms = timeout_ms
            CMultipleReadResult ret
        for k_id in keys:
            c_ids.push_back(k_id)
        c_get_params = get_params_from_py(get_params)
        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")
        with nogil:
            c_libruntime.get().SetTenantIdWithPriority()
            ret = c_libruntime.get().KVGetWithParam(c_ids, c_get_params, c_timeout_ms)
        if not ret.second.OK():
            raise RuntimeError(
                f"failed to kv_get_with_param, "
                f"code: {ret.second.Code()}, module code {ret.second.MCode()}, msg: {ret.second.Msg().decode()}")
        result = []
        for it in ret.first:
            if it == NULL:
                result.append(None)
            else:
                result.append(memoryview(Buffer.make(it)))
        return result

    def kv_del(self, key: Union[str, List[str]]) -> None:
        """
        del value in ds
        :param key: key
        :return: None
        """
        cdef:
            CMultipleDelResult ret
            vector[string] c_ids
        if isinstance(key, str):
            c_ids.push_back(key)
        else:
            for k_id in key:
                c_ids.push_back(k_id)
        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")
        with nogil:
            c_libruntime.get().SetTenantIdWithPriority()
            ret = c_libruntime.get().KVDel(c_ids)
        if not ret.second.OK():
            raise RuntimeError(
                f"failed to kv_del, "
                f"code: {ret.second.Code()}, module code {ret.second.MCode()}, msg: {ret.second.Msg().decode()}")

    def increase_global_reference(self, object_ids: List[str]) -> None:
        """
        increase global reference for object
        :param object_ids: objects
        :return: None
        """
        cdef:
            vector[string] c_ids
            CErrorInfo ret
        for i in object_ids:
            c_ids.push_back(i)
        with nogil:
            CLibruntimeManager.Instance().GetLibRuntime().get().SetTenantIdWithPriority()
            ret = CLibruntimeManager.Instance().GetLibRuntime().get().IncreaseReference(c_ids)
        if not ret.OK():
            raise RuntimeError(
                f"failed to increase, "
                f"code: {ret.Code()}, module code {ret.MCode()}, msg: {ret.Msg().decode()}")

    def decrease_global_reference(self, object_ids: List[str]) -> None:
        """
        decrease global reference for object
        :param object_ids: objects
        :return: None
        """
        cdef vector[string] c_ids
        for i in object_ids:
            c_ids.push_back(i)
        with nogil:
            runtime = CLibruntimeManager.Instance().GetLibRuntime().get()
            if runtime != nullptr:
                runtime.SetTenantIdWithPriority()
                runtime.DecreaseReference(c_ids)

    def invoke_by_name(self, func_meta: FunctionMeta, args: List, opt,
                       return_nums: int, group_info: GroupInfo = None) -> List[str]:
        """
        invoke instance by name
        :param func_meta: function meta
        :param args: args
        :param opt: options
        :param return_objs: return objects
        :param group_info: group info
        :return: return_objs: List[str]
        """
        cdef:
            CErrorInfo error_info
            CFunctionMeta functionMeta
            vector[CInvokeArg] invokeArgs
            CInvokeOptions opts
            vector[CDataObject] returnObjs
            CDataObject returnObj

        # TODO add fundamental type
        for _ in range(return_nums):
            returnObj = CDataObject()
            returnObj.id = "".encode()
            returnObjs.push_back(returnObj)
        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")
        with nogil:
            tenantId = c_libruntime.get().GetTenantId()
        function_meta_from_py(functionMeta, func_meta)
        parse_invoke_args(args, invokeArgs, tenantId)
        parse_invoke_opts(opts, opt, group_info)
        with nogil:
            libruntime = c_libruntime.get()
            libruntime.SetTenantIdWithPriority()
            error_info = libruntime.InvokeByFunctionName(functionMeta, invokeArgs, opts, returnObjs)
        if not error_info.OK():
            raise ValueError(
                f"failed to invoke instance, "
                f"code: {error_info.Code()}, module code {error_info.MCode()}, msg: {error_info.Msg().decode()}")

        _logger.debug("Succeed to invoke function: %s", func_meta)
        return_objs = []
        for i in range(returnObjs.size()):
            return_objs.append(returnObjs.at(i).id.decode())
        return return_objs

    def create_instance(self, func_meta: FunctionMeta, args: List, opt, group_info: GroupInfo = None) -> str:
        """
        create instance
        :param func_meta: function_meta
        :param args: args
        :param opt: options
        :param group_info: group info
        :return: instance id
        """
        cdef:
            pair[CErrorInfo, string] ret
            CFunctionMeta functionMeta
            vector[CInvokeArg] invokeArgs
            CInvokeOptions opts
        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")
        with nogil:
            tenantId = c_libruntime.get().GetTenantId()
        function_meta_from_py(functionMeta, func_meta)
        parse_invoke_args(args, invokeArgs, tenantId)
        parse_invoke_opts(opts, opt, group_info)
        with nogil:
            c_libruntime.get().SetTenantIdWithPriority()
            ret = c_libruntime.get().CreateInstance(functionMeta, invokeArgs, opts)
        if not ret.first.OK():
            raise ValueError(
                f"failed to create instance, "
                f"code: {ret.first.Code()}, module code {ret.first.MCode()}, msg: {ret.first.Msg().decode()}")
        return ret.second.decode()

    def invoke_instance(self, func_meta: FunctionMeta, instance_id: str, args: List,
                        opt, return_nums: int) -> List[str]:
        """
        invoke instance by id
        :param func_meta: function meta
        :param instance_id: instance id
        :param args: args
        :param opt: options
        :return: object ids
        """
        cdef:
            CErrorInfo ret
            CFunctionMeta functionMeta
            vector[CInvokeArg] invokeArgs
            CInvokeOptions opts
            vector[CDataObject] returnObjs
            CDataObject returnObj
            string cinstanceID = instance_id.encode()
        # TODO add fundamental type
        for _ in range(return_nums):
            returnObj = CDataObject()
            returnObj.id = "".encode()
            returnObjs.push_back(returnObj)
        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")
        with nogil:
            tenantId = c_libruntime.get().GetTenantId()
        function_meta_from_py(functionMeta, func_meta)
        parse_invoke_args(args, invokeArgs, tenantId)
        parse_invoke_opts(opts, opt)
        with nogil:
            c_libruntime.get().SetTenantIdWithPriority()
            ret = c_libruntime.get().InvokeByInstanceId(functionMeta, cinstanceID,
                                                                                         invokeArgs, opts, returnObjs)
        if not ret.OK():
            raise ValueError(
                f"failed to invoke instance, "
                f"code: {ret.Code()}, module code {ret.MCode()}, msg: {ret.Msg().decode()}")
        return_objs = []
        for i in range(returnObjs.size()):
            return_objs.append(returnObjs.at(i).id.decode())
        return return_objs

    def cancel(self, object_ids: List[str], allow_force: bool, allow_recursive: bool) -> None:
        """
        cancel task
        :param object_id: object id which need to cancel
        :return: None
        """
        cdef vector[string] c_ids
        for i in object_ids:
            c_ids.push_back(i)
        with nogil:
            CLibruntimeManager.Instance().GetLibRuntime().get().Cancel(c_ids, allow_force, allow_recursive)

    def terminate_instance(self, instance_id: str) -> None:
        """
        terminate instance
        :param instance_id: instance id which need to terminate
        :return: None
        """
        cdef:
            CErrorInfo ret
            string c_id = instance_id
            int sigNo = CSignal.KILLINSTANCE
        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")
        with nogil:
            ret = c_libruntime.get().Kill(c_id, sigNo)
        if not ret.OK():
            raise RuntimeError(
                f"failed to kill instance, "
                f"code: {ret.Code()}, module code {ret.MCode()}, msg: {ret.Msg().decode()}")

    def terminate_instance_sync(self, instance_id: str) -> None:
        """
        terminate instance sync
        :param instance_id: instance id which need to terminate
        :return: None
        """
        cdef:
            CErrorInfo ret
            string c_id = instance_id
            int sigNo = CSignal.KILLINSTANCESYNC
        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")
        with nogil:
            ret = c_libruntime.get().Kill(c_id, sigNo)
        if not ret.OK():
            raise RuntimeError(
                f"failed to kill instance sync, "
                f"code: {ret.Code()}, module code {ret.MCode()}, msg: {ret.Msg().decode()}")

    def snapshot_instance(self, instance_id: str, ttl: int = -1, leave_running: bool = False,
                          function_type: str = "") -> str:
        """
        Create instance snapshot
        :param instance_id: instance id to snapshot
        :param ttl: time-to-live for the snapshot in seconds
        :param leave_running: whether to keep instance running after snapshot
        :param function_type: moduleName.className for actors
        :return: checkpointID
        """
        cdef:
            pair[CErrorInfo, string] ret
            string c_id = instance_id
            CSnapOptions snap_opts

        snap_opts.type = CSnapType.SNAPSHOT
        snap_opts.ttl = ttl
        snap_opts.leaveRunning = leave_running
        if function_type:
            snap_opts.functionType = function_type.encode()

        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")

        with nogil:
            ret = c_libruntime.get().Snapshot(c_id, snap_opts)

        if not ret.first.OK():
            raise RuntimeError(
                f"failed to snapshot instance, "
                f"code: {ret.first.Code()}, module code {ret.first.MCode()}, msg: {ret.first.Msg().decode()}")

        return ret.second.decode()

    def snapstart_instance(self, checkpoint_id: str):
        """
        Start instance from snapshot
        :param checkpoint_id: checkpoint id to restore from
        :return: snapstart response
        """
        cdef:
            pair[CErrorInfo, CSnapstartResponse] ret
            string c_checkpoint_id = checkpoint_id
            CSnapStartOptions snap_start_opts

        snap_start_opts.type = CSnapType.SNAPSHOT

        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")

        with nogil:
            ret = c_libruntime.get().Snapstart(c_checkpoint_id, snap_start_opts)

        if not ret.first.OK():
            raise RuntimeError(
                f"failed to snapstart instance, "
                f"code: {ret.first.Code()}, module code {ret.first.MCode()}, msg: {ret.first.Msg().decode()}")

        return SnapstartResponse(
            instance_id=ret.second.instanceID.decode(),
            snapstart_info=SnapstartInfo(
                route_address=ret.second.snapstartInfo.routeAddress.decode(),
                port_mappings=ret.second.snapstartInfo.portMappings.decode(),
                function_proxy_id=ret.second.snapstartInfo.functionProxyID.decode(),
                node_id=ret.second.snapstartInfo.nodeID.decode(),
                namespace=ret.second.snapstartInfo.namespace_.decode(),
            ))

    def delete_checkpoint(self, checkpoint_id: str) -> None:
        """
        Delete a checkpoint by checkpoint_id
        :param checkpoint_id: checkpoint id to delete
        :return: None
        """
        cdef:
            pair[CErrorInfo, string] ret
            string c_checkpoint_id = checkpoint_id

        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")

        with nogil:
            ret = c_libruntime.get().DeleteCheckpoint(c_checkpoint_id)

        if not ret.first.OK():
            raise RuntimeError(
                f"failed to delete checkpoint, "
                f"code: {ret.first.Code()}, module code {ret.first.MCode()}, msg: {ret.first.Msg().decode()}")

    def list_checkpoints(self, function_type: str = "", namespace: str = "") -> list:
        """
        List checkpoint IDs for the given function type, or all for the current tenant if empty.
        :param function_type: moduleName.className (e.g. "mymodule.Counter"). Empty = all tenant checkpoints.
        :param namespace: namespace filter (empty = default namespace)
        :return: list of checkpoint ID strings
        """
        cdef:
            pair[CErrorInfo, vector[string]] ret
            string c_function_type = function_type.encode()
            string c_ns = namespace.encode()

        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")

        with nogil:
            ret = c_libruntime.get().ListCheckpoints(c_function_type, c_ns)

        if not ret.first.OK():
            raise RuntimeError(
                f"failed to list checkpoints, "
                f"code: {ret.first.Code()}, module code {ret.first.MCode()}, msg: {ret.first.Msg().decode()}")
        return [cp.decode() for cp in ret.second]

    def terminate_group(self, group_name: str) -> None:
        """
        terminate group
        :param group_name: group which need to terminate
        :return: None
        """
        cdef:
            string c_group_name = group_name
        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")
        with nogil:
            c_libruntime.get().GroupTerminate(c_group_name)

    def exit(self) -> None:
        """
        exit current instance. only support in runtime.
        :return: None
        """
        with nogil:
            CLibruntimeManager.Instance().GetLibRuntime().get().Exit()

    def create_stream_producer(self, stream_name: str, config: ProducerConfig) -> Producer:
        """
        create stream producer
        :param stream_name: stream name
        :param config: ProducerConfig
        :return: producer
        """
        cdef:
            CProducerConf cfg
            shared_ptr[CStreamProducer] producer
            CErrorInfo ret
            string cstreamName = stream_name.encode()
        cfg.delayFlushTime = config.delay_flush_time
        cfg.pageSize = config.page_size
        cfg.maxStreamSize = config.max_stream_size
        cfg.autoCleanup = config.auto_clean_up
        cfg.encryptStream = config.encrypt_stream
        cfg.retainForNumConsumers = config.retain_for_num_consumers
        cfg.reserveSize = config.reserve_size
        for key, value in config.extend_config.items():
            cfg.extendConfig.insert(pair[string, string](key, value))
        with nogil:
            CLibruntimeManager.Instance().GetLibRuntime().get().SetTenantIdWithPriority()
            ret = CLibruntimeManager.Instance().GetLibRuntime().get().CreateStreamProducer(cstreamName, cfg, producer)
        if not ret.OK():
            raise RuntimeError(
                f"failed to create stream producer, "
                f"code: {ret.Code()}, module code {ret.MCode()}, msg: {ret.Msg().decode()}")
        return Producer.make(producer)

    def create_stream_consumer(self, stream_name: str, config: SubscriptionConfig) -> Consumer:
        """
        create stream consumer
        :param stream_name: stream name
        :param config: SubscriptionConfig
        :return: consumer
        """
        cdef:
            CSubscriptionConfig cfg
            shared_ptr[CStreamConsumer] consumer
            CErrorInfo ret
            string cstreamName = stream_name.encode()
        cfg.subscriptionName = config.subscription_name
        if config.subscriptionType == SubscriptionType.STREAM:
            cfg.subscriptionType = CSubscriptionType.STREAM
        elif config.subscriptionType == SubscriptionType.ROUND_ROBIN:
            cfg.subscriptionType = CSubscriptionType.ROUND_ROBIN
        elif config.subscriptionType == SubscriptionType.KEY_PARTITIONS:
            cfg.subscriptionType = CSubscriptionType.KEY_PARTITIONS
        else:
            cfg.subscriptionType = CSubscriptionType.UNKNOWN
        for key, value in config.extend_config.items():
            cfg.extendConfig.insert(pair[string, string](key, value))
        with nogil:
            CLibruntimeManager.Instance().GetLibRuntime().get().SetTenantIdWithPriority()
            ret = CLibruntimeManager.Instance().GetLibRuntime().get().CreateStreamConsumer(cstreamName, cfg, consumer)
        if not ret.OK():
            raise RuntimeError(
                f"failed to create stream consumer, "
                f"code: {ret.Code()}, module code {ret.MCode()}, msg: {ret.Msg().decode()}")
        return Consumer.make(consumer)

    def delete_stream(self, stream_name: str) -> None:
        """
        delete stream
        :param stream_name: stream name
        :return: None
        """
        cdef:
            CErrorInfo ret
            string cstreamName = stream_name.encode()
        with nogil:
            CLibruntimeManager.Instance().GetLibRuntime().get().SetTenantIdWithPriority()
            ret = CLibruntimeManager.Instance().GetLibRuntime().get().DeleteStream(cstreamName)
        if not ret.OK():
            raise RuntimeError(
                f"failed to delete stream, "
                f"code: {ret.Code()}, module code {ret.MCode()}, msg: {ret.Msg().decode()}")

    def query_global_producers_num(self, stream_name: str) -> int:
        """
        query global producers num
        :param stream_name: stream name
        :return: producers num
        """
        cdef:
            uint64_t num = 0
            CErrorInfo ret
            string cstreamName = stream_name.encode()
        with nogil:
            CLibruntimeManager.Instance().GetLibRuntime().get().SetTenantIdWithPriority()
            ret = CLibruntimeManager.Instance().GetLibRuntime().get().QueryGlobalProducersNum(cstreamName, num)
        if not ret.OK():
            raise RuntimeError(
                f"failed to query global producers num, "
                f"code: {ret.Code()}, module code {ret.MCode()}, msg: {ret.Msg().decode()}")
        return num

    def query_global_consumers_num(self, stream_name: str) -> int:
        """
        query global consumers num
        :param stream_name: stream name
        :return: consumers num
        """
        cdef:
            uint64_t num = 0
            CErrorInfo ret
            string c_stream_name = stream_name.encode()
        with nogil:
            CLibruntimeManager.Instance().GetLibRuntime().get().SetTenantIdWithPriority()
            ret = CLibruntimeManager.Instance().GetLibRuntime().get().QueryGlobalConsumersNum(c_stream_name, num)
        if not ret.OK():
            raise RuntimeError(
                f"failed to query global consumers num, "
                f"code: {ret.Code()}, module code {ret.MCode()}, msg: {ret.Msg().decode()}")
        return num

    def save_real_instance_id(self, instance_id: str, need_order: bool) -> None:
        """
        save real instance id
        :param instance_id: instance id
        :param need_order: need order
        :return: None
        """
        cdef:
            string c_instance_id = instance_id.encode()
            CInstanceOptions opts
        opts.needOrder = need_order
        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")
        with nogil:
            c_libruntime.get().SaveRealInstanceId(c_instance_id, c_instance_id, opts)

    def get_real_instance_id(self, instance_id: str) -> str:
        """
        get real instance id
        :param instance_id: instance key for instance id
        :return: real instance id
        """
        cdef:
            string c_real_instance_id
            string c_instance_id = instance_id.encode()
        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")
        with nogil:
            c_real_instance_id = c_libruntime.get().GetRealInstanceId(c_instance_id)

        real_instance_id = c_real_instance_id.decode()
        return real_instance_id

    def is_object_existing_in_local(self, object_id: str) -> bool:
        """
        is object existed in local
        :param object_id: object id
        :return: is existed
        """
        cdef:
            bool ret
            string c_object_id = object_id.encode()
        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")
        with nogil:
            ret = c_libruntime.get().IsObjectExistingInLocal(c_object_id)

        return ret

    def save_state(self, timeout_ms: int):
        """
        save actor state
        :param timeout_sec: timeout milliseconds
        :return: None
        """
        cdef:
            int c_timeout_ms = timeout_ms;
            shared_ptr[CBuffer] data
            CErrorInfo c_errror_info

        c_errror_info = dump_instance("".encode(), data)
        check_error_info(c_errror_info, "Failed to save state")
        if data == nullptr:
            raise RuntimeError("Failed to save state. Instance buffer is nullptr.")
        with nogil:
            c_errror_info = CLibruntimeManager.Instance().GetLibRuntime().get().SaveState(data, c_timeout_ms)
        check_error_info(c_errror_info, "Failed to save state")

    def load_state(self, timeout_ms: int):
        """
        load actor state
        :param timeout_ms: timeout milliseconds
        :return: None
        """
        cdef:
            int c_timeout_ms = timeout_ms;
            shared_ptr[CBuffer] data;
            CErrorInfo c_errror_info
        with nogil:
            c_errror_info = CLibruntimeManager.Instance().GetLibRuntime().get().LoadState(data, c_timeout_ms)
        check_error_info(c_errror_info, "Failed to load state")
        c_errror_info = load_instance(data)
        check_error_info(c_errror_info, "Failed to load state")

    def session_wait(self, session_id: str, timeout_ms: int):
        """
        Block until another party calls session_notify for the same session, or timeout.

        Mirrors C++ CLibruntime::SessionWait / JNI sessionWait.
        :return: notify payload bytes, or None on timeout (ERR_SESSION_TIMEOUT)
        """
        if timeout_ms < -1:
            raise ValueError(
                f"Invalid parameter, timeout_ms: {timeout_ms}, expect -1 or >= 0")
        return session_wait_bridge(session_id, <int64_t>timeout_ms)

    def session_notify(self, session_id: str, data: bytes) -> None:
        """
        Wake a thread blocked in session_wait for the same session.

        Mirrors C++ CLibruntime::SessionNotify / JNI sessionNotify.
        """
        session_notify_bridge(session_id, data)

    def create_resource_group(self, vector[unordered_map[string, double]] bundles, string name, string strategy) -> str:
        """
        create resource group
        :param bundles: The bundles in resource group.
        :name: The name of resource group
        :return: Request id
        """
        cdef:
            CResourceGroupSpec c_resource_group_spec
            CErrorInfo c_errror_info
            string c_request_id
        c_resource_group_spec.name = name
        c_resource_group_spec.strategy = strategy
        c_resource_group_spec.bundles = bundles
        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")
        with nogil:
            c_errror_info = c_libruntime.get().CreateResourceGroup(c_resource_group_spec,
                                                                                                     c_request_id)
        check_error_info(c_errror_info, "Failed to create resource group")
        return c_request_id.decode()

    def remove_resource_group(self, name: str):
        """
        remove resource group
        :name: The name of resource group
        :return: None
        """
        cdef:
            string c_resource_group_name = name.encode()
            CErrorInfo c_errror_info
        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")
        with nogil:
            c_errror_info = c_libruntime.get().RemoveResourceGroup(c_resource_group_name)
        check_error_info(c_errror_info, "Failed to remove resource group")

    def wait_resource_group(self, name: str, request_id: str, timeout_seconds: int):
        """
        wait resource group
        :name: The name of resource group
        :request_id: The request id of resource group
        :timeout_seconds: Timeout for waiting create resource group response.
        :return: None
        """
        cdef:
            string c_resource_group_name = name.encode()
            string c_request_id = request_id.encode()
            int c_timeout_seconds
            CErrorInfo c_errror_info
        c_timeout_seconds = timeout_seconds
        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")
        with nogil:
            c_errror_info = c_libruntime.get().WaitResourceGroup(c_resource_group_name,
                                                                                                   c_request_id,
                                                                                                   c_timeout_seconds)
        check_error_info(c_errror_info, "Failed to wait resource group")

    def set_uint64_counter(self, data: UInt64CounterData) -> None:
        """
        set uint64 counter metric
        :param data: UInt64CounterData
        :return: None
        """
        cdef:
            CErrorInfo error_info
            CUInt64CounterData uint64_counter_data
        uint64_counter_data = uint64_counter_data_from_py(data)
        with nogil:
            error_info = CLibruntimeManager.Instance().GetLibRuntime().get().SetUInt64Counter(uint64_counter_data)
        check_error_info(error_info, "Failed to set uint64 counter")

    def reset_uint64_counter(self, data: UInt64CounterData) -> None:
        """
        reset uint64 counter metric
        :param data: UInt64CounterData
        :return: None
        """
        cdef:
            CErrorInfo error_info
            CUInt64CounterData uint64_counter_data
        uint64_counter_data = uint64_counter_data_from_py(data)
        with nogil:
            error_info = CLibruntimeManager.Instance().GetLibRuntime().get().ResetUInt64Counter(uint64_counter_data)
        check_error_info(error_info, "Failed to set uint64 counter")

    def increase_uint64_counter(self, data: UInt64CounterData) -> None:
        """
        increase uint64 counter metric
        :param data: UInt64CounterData
        :return: None
        """
        cdef:
            CErrorInfo error_info
            CUInt64CounterData uint64_counter_data
        uint64_counter_data = uint64_counter_data_from_py(data)
        with nogil:
            error_info = CLibruntimeManager.Instance().GetLibRuntime().get().IncreaseUInt64Counter(uint64_counter_data)
        check_error_info(error_info, "Failed to set uint64 counter")

    def get_value_uint64_counter(self, data: UInt64CounterData) -> int:
        """
        get value of uint64 counter metric
        :param data: UInt64CounterData
        :return: value
        """
        cdef:
            pair[CErrorInfo, int] ret
            CUInt64CounterData uint64_counter_data
        uint64_counter_data = uint64_counter_data_from_py(data)
        with nogil:
            ret = CLibruntimeManager.Instance().GetLibRuntime().get().GetValueUInt64Counter(uint64_counter_data)
        check_error_info(ret.first, "Failed to set uint64 counter")
        return ret.second

    def set_double_counter(self, data: DoubleCounterData) -> None:
        """
        set double counter
        :param data: DoubleCounterData
        :return: None
        """
        cdef:
            CErrorInfo error_info
            CDoubleCounterData double_counter_data
        double_counter_data = double_counter_data_from_py(data)
        with nogil:
            error_info = CLibruntimeManager.Instance().GetLibRuntime().get().SetDoubleCounter(double_counter_data)
        check_error_info(error_info, "Failed to set double counter")

    def reset_double_counter(self, data: DoubleCounterData) -> None:
        """
        reset double counter
        :param data: DoubleCounterData
        :return: None
        """
        cdef:
            CErrorInfo error_info
            CDoubleCounterData double_counter_data
        double_counter_data = double_counter_data_from_py(data)
        with nogil:
            error_info = CLibruntimeManager.Instance().GetLibRuntime().get().ResetDoubleCounter(double_counter_data)
        check_error_info(error_info, "Failed to set double counter")

    def increase_double_counter(self, data: DoubleCounterData) -> None:
        """
        increase double counter
        :param data: DoubleCounterData
        :return: None
        """
        cdef:
            CErrorInfo error_info
            CDoubleCounterData double_counter_data
        double_counter_data = double_counter_data_from_py(data)
        with nogil:
            error_info = CLibruntimeManager.Instance().GetLibRuntime().get().IncreaseDoubleCounter(double_counter_data)
        check_error_info(error_info, "Failed to set double counter")

    def get_value_double_counter(self, data: DoubleCounterData) -> float:
        """
        get value of double counter
        :param data: DoubleCounterData
        :return: value
        """
        cdef:
            pair[CErrorInfo, float] ret
            CDoubleCounterData double_counter_data
        double_counter_data = double_counter_data_from_py(data)
        with nogil:
            ret = CLibruntimeManager.Instance().GetLibRuntime().get().GetValueDoubleCounter(double_counter_data)
        check_error_info(ret.first, "Failed to set double counter")
        return ret.second

    def set_gauge(self, data: GaugeData) -> None:
        """
        set gauge metric
        :param data: GaugeData
        :return: None
        """
        cdef:
            CErrorInfo error_info
            CGaugeData gauge_data
        gauge_data = gauge_data_from_py(data)
        with nogil:
            error_info = CLibruntimeManager.Instance().GetLibRuntime().get().SetGauge(gauge_data)
        check_error_info(error_info, "Failed to set gauge")

    def increase_gauge(self, data: GaugeData) -> None:
        """
        increase gauge metric
        :param data: GaugeData
        :return: None
        """
        cdef:
            CErrorInfo error_info
            CGaugeData gauge_data
        gauge_data = gauge_data_from_py(data)
        with nogil:
            error_info = CLibruntimeManager.Instance().GetLibRuntime().get().IncreaseGauge(gauge_data)
        check_error_info(error_info, "Failed to increase gauge")

    def decrease_gauge(self, data: GaugeData) -> None:
        """
        decrease gauge metric
        :param data: GaugeData
        :return: None
        """
        cdef:
            CErrorInfo error_info
            CGaugeData gauge_data
        gauge_data = gauge_data_from_py(data)
        with nogil:
            error_info = CLibruntimeManager.Instance().GetLibRuntime().get().DecreaseGauge(gauge_data)
        check_error_info(error_info, "Failed to decrease gauge")

    def get_value_gauge(self, data: GaugeData) -> float:
        """
        get value of gauge
        :param data: GaugeData
        :return: value
        """
        cdef:
            pair[CErrorInfo, float] ret
            CGaugeData gauge_data
        gauge_data = gauge_data_from_py(data)
        with nogil:
            ret = CLibruntimeManager.Instance().GetLibRuntime().get().GetValueGauge(gauge_data)
        check_error_info(ret.first, "Failed to get gauge")
        return ret.second

    def report_gauge(self, data: GaugeData) -> None:
        """
        report gauge metric
        :param data: GaugeData
        :return: None
        """
        cdef:
            CErrorInfo error_info
            CGaugeData gauge_data
        gauge_data = gauge_data_from_py(data)
        with nogil:
            error_info = CLibruntimeManager.Instance().GetLibRuntime().get().ReportGauge(gauge_data)
        check_error_info(error_info, "Failed to report gauge")

    def set_alarm(self, name: str, description: str, info: AlarmInfo) -> None:
        """
        set alarm
        :param name: The name of alarm metrics
        :param description: The description of alarm metrics
        :param info: The alarm info
        : return: None
        """
        cdef:
            string c_name = name.encode()
            string c_description = description.encode()
            CErrorInfo error_info
            CAlarmInfo alarm_info
        alarm_info = alarm_info_from_py(info)
        with nogil:
            error_info = CLibruntimeManager.Instance().GetLibRuntime().get().SetAlarm(c_name, c_description,
                                                                                      alarm_info)
        check_error_info(error_info, "Failed to set alarm")

    def peek_object_ref_stream(self, generator_id: str, blocking: bool, timeout_ms: int):
        """
        peek_object_ref_stream
        :param timeout_ms
        :param generator_id
        :return: object_id
        """
        cdef:
            pair[CErrorInfo, string] ret
            string c_generator_id = generator_id.encode()
            shared_ptr[CBuffer] c_buffer
        with nogil:
            ret = CLibruntimeManager.Instance().GetLibRuntime().get().PeekObjectRefStream(c_generator_id, blocking)

        if not ret.first.OK():
            if error_code_from_cpp(ret.first.Code()) == ErrorCode.ERR_GENERATOR_FINISHED:
                self.decrease_global_reference([ret.second.decode()])
                raise GeneratorEndError(
                    f"gernerator stop, "
                    f"code: {ret.first.Code()}, module code {ret.first.MCode()}, msg: {ret.first.Msg().decode()}")
            else:
                result = []
                if ret.first.Code() == CErrorCode.ERR_USER_FUNCTION_EXCEPTION:
                    c_stack_trace_info = ret.first.GetStackTraceInfos()
                    it_sti = c_stack_trace_info.begin()
                    while it_sti != c_stack_trace_info.end():
                        if dereference(it_sti).Type().decode() == "YRInvokeError":
                            c_buffer = dynamic_pointer_cast[CBuffer, NativeBuffer](
                                make_shared[NativeBuffer](dereference(it_sti).Message().size()))
                            memory_copy(c_buffer, dereference(it_sti).Message().data(),
                                        dereference(it_sti).Message().size())
                            result.append(Buffer.make(c_buffer))
                            return result
                        postincrement(it_sti)
                raise RuntimeError(
                    f"failed to peek object, "
                    f"code: {ret.first.Code()}, module code {ret.first.MCode()}, msg: {ret.first.Msg().decode()}")
        obj_id = ret.second.decode()
        return obj_id

    def generate_group_name(self) -> str:
        """
        generate group name.
        Returns:
            group name
        """
        cdef:
            string c_group_name
        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")
        with nogil:
            c_group_name = c_libruntime.get().GenerateGroupName()
        group_name = c_group_name.decode()
        return group_name

    def get_instances(self, obj_id, group_name) -> List[str]:
        """
        get instance id list.
        Returns:
            instance id list
        """
        cdef:
            string c_obj_id = obj_id.encode()
            string c_group_name = group_name.encode()
            pair[vector[string], CErrorInfo] ret
        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")
        with nogil:
            ret = c_libruntime.get().GetInstances(c_obj_id, c_group_name)
        if not ret.second.OK():
            raise RuntimeError(
                f"failed to get instances, "
                f"code: {ret.second.Code()}, module code {ret.second.MCode()}, msg: {ret.second.Msg().decode()}")
        return [c_instance_id.decode() for c_instance_id in ret.first]

    def resource_group_table(self, resource_group_id):
        """
        query resource group info
        """
        cdef:
            pair[CErrorInfo, CResourceGroupUnit] ret
            string id = resource_group_id.encode()
            CRgInfo rg_info
            CBundleInfo bundle
            CResource resource
            CScalar scalar
            size_t i
        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")
        ret = c_libruntime.get().GetResourceGroupTable(id)
        if not ret.first.OK():
            raise RuntimeError(
                f"failed to get resources, "
                f"code: {ret.first.Code()}, module code {ret.first.MCode()}, msg: {ret.first.Msg().decode()}")

        return parse_rginfo_to_python(ret.second)

    def resources(self):
        """
        get resources info list.
        Returns:
            resources info list
        """
        cdef:
            pair[CErrorInfo, vector[CResourceUnit]] ret
            vector[string] label_values
        ret = CLibruntimeManager.Instance().GetLibRuntime().get().GetResources()
        if not ret.first.OK():
            raise RuntimeError(
                f"failed to get resources, "
                f"code: {ret.first.Code()}, module code {ret.first.MCode()}, msg: {ret.first.Msg().decode()}")
        capacity = {}
        result = []
        for it in ret.second:
            res = {}
            res['id'] = it.id.decode()
            res['status'] = it.status
            capacity = {}
            for r in it.capacity:
                name = r[0].decode()
                capacity[name] = r[1]
            res['capacity'] = capacity
            allocatable = {}
            for r in it.allocatable:
                name = r[0].decode()
                allocatable[name] = r[1]
            res['allocatable'] = allocatable
            labels = {}
            for r in it.nodeLabels:
                key = r[0].decode()
                label_values = r[1]
                labels[key] = []
                for value in label_values:
                    labels[key].append(value.decode())
            res['labels'] = labels
            result.append(res)
        return result

    def query_named_instances(self):
        """
        """
        cdef pair[CErrorInfo, QueryNamedInsResponse] ret
        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")
        ret = c_libruntime.get().QueryNamedInstances()

        if not ret.first.OK():
            raise RuntimeError(
                f"failed to get queryInstances, "
                f"code: {ret.first.Code()}, module code {ret.first.MCode()}, msg: {ret.first.Msg().decode()}"
            )

        cdef QueryNamedInsResponse rsp = ret.second
        name_result = [rsp.names(i).decode() for i in range(rsp.names_size())]
        return name_result

    def get_node_ip_address(self):
        """
        get node ip address info list.
        Returns:
            node ip address
        """
        cdef:
            pair[CErrorInfo, string] ret
        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")
        ret = c_libruntime.get().GetNodeIpAddress()
        if not ret.first.OK():
            raise RuntimeError(
                f"failed to get node ip address, "
                f"code: {ret.first.Code()}, module code {ret.first.MCode()}, msg: {ret.first.Msg().decode()}")
        return ret.second.decode()

    def get_node_id(self):
        cdef pair[CErrorInfo, string] ret
        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")
        ret = c_libruntime.get().GetNodeId()

        if not ret.first.OK():
            raise RuntimeError(
                f"failed to get node_id, "
                f"code: {ret.first.Code()}, module code {ret.first.MCode()}, msg: {ret.first.Msg().decode()}"
            )

        return ret.second.decode()

    def get_namespace(self):
        cdef string ret
        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")
        ret = c_libruntime.get().GetNameSpace()
        return ret.decode()

    def get_function_group_context(self) -> yr.FunctionGroupContext:
        cdef:
            CFunctionGroupRunningInfo info
        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")
        with nogil:
            info = c_libruntime.get().GetFunctionGroupRunningInfo()
        return function_group_running_info_from_cpp(info)

    def get_instance_by_name(self, name, ns, timeout):
        cdef:
            pair[CFunctionMeta, CErrorInfo] ret
            string cinstanceID
            int sigNo = CSignal.KILLINSTANCESYNC
            string cname = name.encode()
            string cns = ns.encode()
            int ctimeout = timeout
        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")
        yr_ns = self.get_namespace()
        cinstanceID = (ns + "-" + name if ns else yr_ns + "-" + name).encode()
        with nogil:
            c_libruntime.get().SetTenantIdWithPriority()
            ret = c_libruntime.get().GetInstance(cname, cns, ctimeout)
        if not ret.second.OK():
            if ret.second.IsTimeout():
                raise TimeoutError(ret.second.Msg().decode())
            raise ValueError(
                f"failed to get instance by name: {cinstanceID}, "
                f"code: {ret.second.Code()}, module code {ret.second.MCode()}, msg: {ret.second.Msg().decode()}")
        return function_meta_from_cpp(ret.first)

    def is_local_instances(self, instance_ids: List[str]) -> bool:
        cdef:
            vector[string] c_instance_ids
            bool ret
        for instance_id in instance_ids:
            c_instance_ids.push_back(instance_id.encode())
        cdef shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        if c_libruntime == nullptr:
            raise RuntimeError("already finalized")
        with nogil:
            ret = c_libruntime.get().IsLocalInstances(c_instance_ids)
        return ret

    def create_buffer(self, buffer_size: int) -> Tuple[str, SharedBuffer]:
        cdef:
            uint64_t c_size = buffer_size
            shared_ptr[CBuffer] c_buffer
        with nogil:
            CLibruntimeManager.Instance().GetLibRuntime().get().SetTenantIdWithPriority()
            ret = CLibruntimeManager.Instance().GetLibRuntime().get().CreateBuffer(c_size, c_buffer)

        if not ret.first.OK():
            raise RuntimeError(f"failed to create buffer, code: {ret.first.Code()}, "
                               f"module code: {ret.first.MCode()}, msg: {ret.first.Msg().decode()}")
        with nogil:
            result = c_buffer.get().Publish()
        if not result.OK():
            raise RuntimeError(f"failed to publish, code: {result.Code()}, "
                               f"module code: {result.MCode()}, msg: {result.Msg().decode()}")
        return ret.second.decode("utf-8"), SharedBuffer.make(c_buffer)

    def get_buffer(self, obj_id: str)-> SharedBuffer:
        cdef:
            vector[string] c_ids
            int c_timeout = -1
        c_ids.push_back(obj_id)
        with nogil:
            CLibruntimeManager.Instance().GetLibRuntime().get().SetTenantIdWithPriority()
            ret = CLibruntimeManager.Instance().GetLibRuntime().get().GetBuffers(c_ids, c_timeout, False)
        if not ret.first.OK():
            raise RuntimeError(f"failed to get buffer, code: {ret.first.Code()}, "
                               f"module code: {ret.first.MCode()}, msg: {ret.first.Msg().decode()}")
        return SharedBuffer.make(ret.second.front())

    def accelerate(self, group_name: str, handle: Handle):
        cdef:
            vector[string] c_instance_ids
            CAccelerateMsgQueueHandle c_handle
            string c_group_name = group_name.encode()

        c_handle = message_queue_handle_from_py(handle)
        with nogil:
            ret = CLibruntimeManager.Instance().GetLibRuntime().get().Accelerate(c_group_name, c_handle, handle_return_object_callback)
        if not ret.OK():
            raise RuntimeError(
                f"failed to accelerate, code: {ret.Code()}, "
                f"module code: {ret.MCode()}, msg: {ret.Msg().decode()}")

    def add_return_object(self, obj_ids: List[str]):
        cdef:
            vector[string] c_obj_ids
            bool ret
        for obj_id in obj_ids:
            c_obj_ids.push_back(obj_id.encode())
        with nogil:
            ret = CLibruntimeManager.Instance().GetLibRuntime().get().AddReturnObject(c_obj_ids)
        return ret

    def create_group(self, group_name: str, group_opts: GroupOptions):
        cdef:
            string c_group_name = group_name.encode()
            CGroupOptions c_group_options
        c_group_options = group_options_from_py(group_name, group_opts)
        with nogil:
            ret = CLibruntimeManager.Instance().GetLibRuntime().get().GroupCreate(c_group_name, c_group_options)
        if not ret.OK():
            raise RuntimeError(
                f"failed to create group, code: {ret.Code()}, "
                f"module code: {ret.MCode()}, msg: {ret.Msg().decode()}")

    def wait_group(self, group_name: str):
        cdef:
            string c_group_name = group_name.encode()
        with nogil:
            ret = CLibruntimeManager.Instance().GetLibRuntime().get().GroupWait(c_group_name)
        if not ret.OK():
            raise RuntimeError(
                f"failed to wait group, code: {ret.Code()}, "
                f"module code: {ret.MCode()}, msg: {ret.Msg().decode()}")

    def suspend_group(self, group_name: str):
        cdef:
            string c_group_name = group_name.encode()
        with nogil:
            ret = CLibruntimeManager.Instance().GetLibRuntime().get().GroupSuspend(c_group_name)
        if not ret.OK():
            raise RuntimeError(
                f"failed to suspend group, code: {ret.Code()}, "
                f"module code: {ret.MCode()}, msg: {ret.Msg().decode()}")

    def resume_group(self, group_name: str):
        cdef:
            string c_group_name = group_name.encode()
        with nogil:
            ret = CLibruntimeManager.Instance().GetLibRuntime().get().GroupResume(c_group_name)
        if not ret.OK():
            raise RuntimeError(
                f"failed to resume group, code: {ret.Code()}, "
                f"module code: {ret.MCode()}, msg: {ret.Msg().decode()}")


def notify_generator_result(generator_id, index, output, error_info):
    """
    notify_generator_result
    :param generator_id
    :param index
    :param output
    :return ErrorInfo
    """
    object_id = generate_random_id()

    cdef:
        CErrorInfo ret
        int c_index= index
        string c_generator_id = generator_id.encode()
        string c_object_id = object_id.encode()
        shared_ptr[CDataObject] dataObj
        shared_ptr[CBuffer] c_buffer
        CErrorInfo c_error_info
        CErrorInfo c_result_err
        vector[string] nested_ids
        unordered_set[string] nested_ids_set
        uint64_t total_native_buffer_size = 0

    c_result_err = error_info_from_py(error_info)
    dataObj = make_shared[CDataObject](c_object_id)
    dataObj.get().alwaysNative = True
    serialized_object = _serialization_ctx.serialize(output)
    data_bytes = serialized_object.to_bytes()
    meta_size = constants.METALEN
    data_size = serialized_object.total_bytes - constants.METALEN

    c_error_info = CLibruntimeManager.Instance().GetLibRuntime().get().AllocReturnObject(
            dataObj, meta_size, data_size, nested_ids, total_native_buffer_size)

    if c_error_info.OK():
        c_buffer = dataObj.get().buffer
        c_error_info = write2buffer(c_buffer, serialized_object, nested_ids_set)
    if c_error_info.OK():
        c_error_info = CLibruntimeManager.Instance().GetLibRuntime().get().NotifyGeneratorResult(c_generator_id, c_index, dataObj, c_result_err)
    if not c_error_info.OK():
        raise RuntimeError(
            f"failed to notify gennerator result, "
            f"code: {ret.Code()}, module code {ret.MCode()}, msg: {ret.Msg().decode()}")



def notify_generator_finished(generator_id, number_result):
    """
    notify_generator_finished
    :param generator_id
    :param number_result
    :return ErrorInfo
    """

    cdef:
        string c_generator_id = generator_id.encode()
        int c_number_result = number_result;
        CErrorInfo ret

    with nogil:
        ret = CLibruntimeManager.Instance().GetLibRuntime().get().NotifyGeneratorFinished(c_generator_id, c_number_result)

    if not ret.OK():
        raise RuntimeError(
            f"failed to notify generator finished, "
            f"code: {ret.Code()}, module code {ret.MCode()}, msg: {ret.Msg().decode()}")

cdef cluster_access_info_cpp_to_py(const CClusterAccessInfo & c_cluster_info):
    return {
        "serverAddr": c_cluster_info.serverAddr.decode(),
        "dsAddr": c_cluster_info.dsAddr.decode(),
        "inCluster": c_cluster_info.inCluster
    }

cdef CClusterAccessInfo cluster_access_info_py_to_cpp(dict info):
    cdef CClusterAccessInfo c_cluster_info = CClusterAccessInfo()
    if 'serverAddr' in info:
        c_cluster_info.serverAddr = info['serverAddr'].encode('utf-8')
    if 'dsAddr' in info:
        c_cluster_info.dsAddr = info['dsAddr'].encode('utf-8')
    if 'inCluster' in info:
        c_cluster_info.inCluster = info['inCluster']
    return c_cluster_info


def auto_get_cluster_access_info(dict info, args):
    cdef:
        vector[string] c_args
        CClusterAccessInfo c_info
        CClusterAccessInfo result
    for arg in args:
        c_args.push_back(arg.encode())
    c_info = cluster_access_info_py_to_cpp(info)
    result = AutoGetClusterAccessInfo(c_info, c_args)
    return cluster_access_info_cpp_to_py(result)


def get_request_and_instance_id():
    """
    Get (requestId, instanceId) of current runtime context.
    """
    cdef:
        pair[string, string] ret
        shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
    if c_libruntime == nullptr:
        raise RuntimeError("already finalized")
    ret = c_libruntime.get().GetRequestAndInstanceID()
    return ret.first.decode(), ret.second.decode()


def stream_write(stream_message: str, request_id: str, instance_id: str) -> None:
    """
    Write SSE stream message.
    """
    cdef:
        string c_stream_message = stream_message.encode()
        string c_request_id = request_id.encode()
        string c_instance_id = instance_id.encode()
        shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
        CErrorInfo ret
    if c_libruntime == nullptr:
        raise RuntimeError("already finalized")
    with nogil:
        ret = c_libruntime.get().StreamWrite(c_stream_message, c_request_id, c_instance_id)
    if not ret.OK():
        raise RuntimeError(
            f"failed to stream_write, "
            f"code: {ret.Code()}, module code {ret.MCode()}, msg: {ret.Msg().decode()}"
        )


def load_current_session(session_id: str) -> Optional[str]:
    """
    Load current invocation session JSON from libruntime's active session cache.
    """
    if session_id is None or session_id == "":
        raise ValueError("session_id cannot be None or empty")
    cdef:
        string c_session_id = session_id.encode()
        pair[string, CErrorInfo] ret
        shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
    if c_libruntime == nullptr:
        raise RuntimeError("already finalized")
    with nogil:
        ret = c_libruntime.get().LoadCurrentSession(c_session_id)
    if not ret.second.OK():
        raise RuntimeError(
            f"failed to load_current_session, "
            f"code: {ret.second.Code()}, module code: {ret.second.MCode()}, msg: {ret.second.Msg().decode()}"
        )
    result = ret.first.decode()
    return result if result else None


def update_current_session(session_id: str, session_json: str) -> None:
    """
    Update current invocation session JSON in libruntime's active session cache.
    """
    if session_id is None or session_id == "":
        raise ValueError("session_id cannot be None or empty")
    if session_json is None or session_json == "":
        raise ValueError("session_json cannot be None or empty")
    cdef:
        string c_session_id = session_id.encode()
        string c_session_json = session_json.encode()
        CErrorInfo ret
        shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
    if c_libruntime == nullptr:
        raise RuntimeError("already finalized")
    with nogil:
        ret = c_libruntime.get().UpdateCurrentSession(c_session_id, c_session_json)
    if not ret.OK():
        raise RuntimeError(
            f"failed to update_current_session, "
            f"code: {ret.Code()}, module code: {ret.MCode()}, msg: {ret.Msg().decode()}"
        )


def session_wait(session_id: str, timeout_ms: int):
    """
    API-level session wait.
    """
    if timeout_ms < -1:
        raise ValueError(
            f"Invalid parameter, timeout_ms: {timeout_ms}, expect -1 or >= 0")
    return session_wait_bridge(session_id, <int64_t>int(timeout_ms))


def session_notify(session_id: str, data: bytes) -> None:
    """
    API-level session notify.
    """
    session_notify_bridge(session_id, data)


def is_session_interrupted(session_id: str) -> bool:
    """
    Whether the session wait/notify context was interrupted.
    """
    if session_id is None or session_id == "":
        raise ValueError("session_id cannot be None or empty")
    cdef:
        string c_session_id = session_id.encode()
        bint ret
        shared_ptr[CLibruntime] c_libruntime = CLibruntimeManager.Instance().GetLibRuntime()
    if c_libruntime == nullptr:
        raise RuntimeError("already finalized")
    with nogil:
        c_libruntime.get().SetTenantIdWithPriority()
        ret = c_libruntime.get().IsSessionInterrupted(c_session_id)
    return ret