def find_schema_by_id(self, topic_id: TopicId, tenant_id: TenantId) -> Optional[TopicSchema]:
		if not self.principalService.is_super_admin():
			if self.principalService.get_tenant_id() != tenant_id:
				raise Exception('Forbidden')

		schema = CacheService.topic().get_schema(topic_id)
		if schema is not None:
			if schema.get_topic().tenantId != tenant_id:
				return None
			return schema

		storage_service = TopicStorageService(ask_meta_storage(), ask_snowflake_generator(), self.principalService)
		storage_service.begin_transaction()
		try:
			# noinspection PyTypeChecker
			topic: Topic = storage_service.find_by_id(topic_id)
			if topic is None:
				return None

			CacheService.topic().put(topic)
			schema = CacheService.topic().get_schema(topic.topicId)
			if schema is not None:
				if schema.get_topic().tenantId != tenant_id:
					return None
			return schema
		finally:
			storage_service.close_transaction()
	def find_should_monitored(self, tenant_id: TenantId) -> List[Topic]:
		storage_service = TopicStorageService(ask_meta_storage(), ask_snowflake_generator(), self.principalService)
		storage_service.begin_transaction()
		try:
			# noinspection PyTypeChecker
			topics = storage_service.find_all(tenant_id)
			# only business topics need to be monitored
			return ArrayHelper(topics).filter(lambda x: x.kind == TopicKind.BUSINESS).to_list()
		finally:
			storage_service.close_transaction()
def heart_beat_on_topics() -> None:
    topics = CacheService.topic().all()
    topic_service = TopicService(ask_meta_storage(), ask_snowflake_generator(),
                                 ask_super_admin())
    topic_service.begin_transaction()
    try:
        for topic in topics:
            loaded: Optional[Topic] = topic_service.find_by_id(topic.topicId)
            if loaded is None:
                CacheService.topic().remove(topic.topicId)
            elif loaded.lastModifiedAt > topic.lastModifiedAt or loaded.version > topic.version:
                CacheService.topic().put(loaded)
    finally:
        topic_service.close_transaction()
	def find_by_id(self, topic_id: TopicId) -> Optional[Topic]:
		topic = CacheService.topic().get(topic_id)
		if topic is not None:
			if topic.tenantId != self.principalService.get_tenant_id():
				raise DataKernelException(
					f'Topic[id={topic_id}] not belongs to current tenant[id={self.principalService.get_tenant_id()}].')
			return topic

		storage_service = TopicStorageService(ask_meta_storage(), ask_snowflake_generator(), self.principalService)
		storage_service.begin_transaction()
		try:
			# noinspection PyTypeChecker
			topic: Topic = storage_service.find_by_id(topic_id)
			if topic is None:
				return None

			CacheService.topic().put(topic)
			return topic
		finally:
			storage_service.close_transaction()