Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Azure Adapter Cold Start Fix #1167

Open
yeung1213 opened this issue Jul 25, 2024 · 0 comments
Open

Azure Adapter Cold Start Fix #1167

yeung1213 opened this issue Jul 25, 2024 · 0 comments

Comments

@yeung1213
Copy link

spring is not loaded before the first request. Can we add static { initialize(); } inside the class AzureFunctionInstanceInjector

/*
 * Copyright 2021-2022 the original author or authors.
 *
 * 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
 *
 *      https://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.
 */

package org.springframework.cloud.function.adapter.azure;

import java.util.Map;

import com.microsoft.azure.functions.spi.inject.FunctionInstanceInjector;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.boot.ResourceBanner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.cloud.function.utils.FunctionClassUtils;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;

/**
 * The instance factory used by the Spring framework to initialize Azure function instance. It is waived with the Azure
 * Java Worker through the META-INFO/services/com.microsoft.azure.functions.spi.inject.FunctionInstanceInjector service
 * hook. The Azure Java Worker delegates scans the classpath for service definition and delegates the function class
 * creation to this instance factory.
 * @author Christian Tzolov
 * @since 3.2.9
 */
public class AzureFunctionInstanceInjector implements FunctionInstanceInjector {

	private static Log logger = LogFactory.getLog(AzureFunctionInstanceInjector.class);

	private static ConfigurableApplicationContext APPLICATION_CONTEXT;

	static {
		initialize();
	}

	/**
	 * This method is called by the Azure Java Worker on every function invocation. The Worker sends in the classes
	 * annotated with @FunctionName annotations and allows the Spring framework to initialize the function instance as a
	 * Spring Bean and return the instance. Then the Worker uses the created instance to invoke the function.
	 * @param functionClass the class that contains customer Azure functions (e.g. @FunctionName annotated )
	 * @param <T> customer Azure functions class type
	 * @return the instance that will be invoked on by azure functions java worker
	 * @throws Exception any exception that is thrown by the Spring framework during instance creation
	 */
	@Override
	public <T> T getInstance(Class<T> functionClass) throws Exception {
		try {
			// Backward compatibility workaround. If the function class is of type FunctionInvoker then create plain
			// Java instance and delegate to FunctionInvoker adaptor approach.
			if (ClassUtils.isAssignable(FunctionInvoker.class, functionClass)) {
				return functionClass.getDeclaredConstructor().newInstance();
			}

			initialize();

			Map<String, T> azureFunctionBean = APPLICATION_CONTEXT.getBeansOfType(functionClass);
			if (CollectionUtils.isEmpty(azureFunctionBean)) {
				throw new IllegalStateException(
						"Failed to retrieve Bean instance for: " + functionClass
								+ ". The class should be annotated with @Component to let the Spring framework initialize it!");
			}
			return azureFunctionBean.entrySet().iterator().next().getValue();
		}
		catch (Exception e) {
			if (APPLICATION_CONTEXT != null) {
				APPLICATION_CONTEXT.close();
			}
			throw new IllegalStateException("Failed to initialize", e);
		}
	}

	/**
	 * Create a static Application Context instance shared between multiple function invocations.
	 */
	private static void initialize() {
		synchronized (AzureFunctionInstanceInjector.class.getName()) {
			if (APPLICATION_CONTEXT == null) {
				Class<?> springConfigurationClass = FunctionClassUtils.getStartClass();
				logger.info("Initializing: " + springConfigurationClass);
				APPLICATION_CONTEXT = springApplication(springConfigurationClass).run();
			}
		}
	}

	private static SpringApplication springApplication(Class<?> configurationClass) {
		SpringApplication application = new org.springframework.cloud.function.context.FunctionalSpringApplication(
				configurationClass);
		application.setWebApplicationType(WebApplicationType.NONE);
		application.setBanner(new ResourceBanner(
				new DefaultResourceLoader().getResource("classpath:/spring-azure-function-banner.txt")));
		return application;
	}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant