Spring Boot 2.6.6 - Actuator API Reference
I checked the above link and unable to find the /actuator/pause endpoint. I was not sure if it was my app that was causing the issue, so I created a new MVP from spring initializer and even then pause endpoint is not there.
I remember that there used to be a POST endpoint /actuator/pause, but how do I enable this on newer versions of Spring Boot(2.6.6 above)?
The below is my MVP's code.
build.gradle
plugins {
id 'org.springframework.boot' version '2.6.6'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
maven { url 'https://repo.spring.io/milestone' }
maven { url 'https://repo.spring.io/snapshot' }
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
tasks.named('test') {
useJUnitPlatform()
}
application.yml
management:
endpoints.web.exposure.include: '*'
endpoint:
pause.enabled: true
restart.enabled: true
resume.enabled: true
shutdown.enabled: true
And once I start the app and hit
curl --location --request POST 'localhost:8080/actuator/pause', its sending 404.
You'll need to make sure that Spring Cloud Commons is included in your project dependencies, since it looks like that's the library that supplies the actuator/pause endpoint (https://docs.spring.io/spring-cloud-commons/docs/current/reference/html/#endpoints).
As the documentation additionally notes:
If you disable the /actuator/restart endpoint then the /actuator/pause and /actuator/resume endpoints will also be disabled since they are just a special case of /actuator/restart.
It looks like you should add the following dependency to your build.gradle file
implementation 'org.springframework.cloud:spring-cloud-starter:3.1.1
You can see that RestartEndpoint and
RestartEndpoint.PauseEndpoint classes actually are defined in this package.
Obviously you should change the application.yml like this:
management:
endpoints.web.exposure.include: '*'
endpoint:
pause:
enabled: true
restart:
enabled: true
It's easy to support it by yourself.
#RestController
#RequestMapping("/health")
public class HealthController implements HealthIndicator {
private Health health = Health.up().build();
#RequestMapping("/pause")
#ResponseBody
public String pause() {
health = Health.down().build();
return "success";
}
#RequestMapping("/start")
#ResponseBody
public String start() {
health = Health.up().build();
return "success";
}
#Override
public Health health() {
return health;
}
}
Related
I tried to use the annotation #RefreshScope on my rest controller:
#RestController
#RefreshScope
public class SpringCloudControllerTest {
#Value("${data}")
private String value;
#GetMapping
public ResponseEntity<String> testPropertiesFile(){
return ResponseEntity.ok(value);
}
the #Value annotation refers the application.properties on my remote repository:
management.endpoints.web.exposure.include=*
data=2
if i change my file in this way:
management.endpoints.web.exposure.include=*
data=3
and run the request on my client side http://localhost:8081/actuator/refresh
the response is just:
[
"config.client.version"
]
I don't see any response about my changes and if i run the request
localhost:8081
the response is always "2"
these are my dependency on client side:
compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-config', version: '2.2.6.RELEASE'
compile group: 'org.springframework.boot', name: 'spring-boot-starter-actuator', version:'2.3.7.RELEASE'
thank you all
Solved.
I change my application name file (client side) from application.yml to bootstrap.yml
Now when i run localhost:8081/actuator/refresh i have got this response
[
"config.client.version",
"data",
"spring.cloud.bootstrap.enabled"
]
thank you all
Currently, I am doing a small project in which I need to use Spring Boot and FreeMarker template engine. I have tried different ways but I still cannot return a FreeMarker view from Spring Boot. My project uses Gradle as the build tool, here's what's inside:
build.gradle:
plugins {
id 'org.springframework.boot' version '2.3.3.RELEASE'
id 'java'
}
apply plugin: 'io.spring.dependency-management'
sourceCompatibility = 11
repositories {
mavenCentral()
}
sourceSets.main.resources.srcDirs = ["src/resources"]
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
compile("org.springframework.boot:spring-boot-starter-web")
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'org.springframework.boot:spring-boot-starter-freemarker'
}
Here is my method which I expect to redirect to the FreeMarker view with a list, instead, when I send a GET request to this URL, I just get the "index" string displayed:
#GetMapping(path = "/code/latest")
public String getTop10LatestCode(#ModelAttribute("model") ModelMap model) {
model.addAttribute("codes", codes.subList(Math.max(0, codes.size() - 10), Math.max(codes.size() - 1, 0)));
return "index";
}
Here is my application.properties file:
server.port=8889
management.endpoints.web.exposure.include=*
management.endpoint.shutdown.enabled=true
spring.freemarker.template-loader-path=classpath:/templates/
spring.freemarker.suffix=.ftlh
My FreeMarker view is already under the templates folder inside the resources folder.
Here is my project structure:
Any help would be much appreciated, thanks.
I have figured it out, my class is annotated with the #RestController annotation, which itself is the combination of the #Controller and #ResponseBody annotations, because each method in my class will have a response body returned, even the one that I posted here, that's why it returns the body, hence returns index. I need to change my #RestController to #Controller and the problem solved.
I have a grails 3.2.0 web profile app. I want to connect to a separate micronaut app which is running fine and is connected properly to consul locally.
Here is my micronaut controller :
#Controller("/test")
class TestController {
#Get("/")
def index(){
return "Welcome to micronaut"
}
#Get("/test")
Single<String> test() {
return Single.just("Hello There")
}
}
Here is my grails controller :
class CardClientController {
#Autowired
NewCardClient newCardClient
def index() {
def result = newCardClient.getCards()
respond result
}
}
NewCardClient interface :
#Client("firstmicroservice")
public interface NewCardClient {
#Get("/test/test")
Single<String> getCards();
}
dependencies i've added in grails app :
compile 'io.micronaut:inject-java:1.0.0.M1'
compile 'io.micronaut:discovery-client:1.0.0.M1'
compile 'io.micronaut:spring:1.0.0.M1'
runtime 'io.micronaut:runtime:1.0.0.M1'
When i hit the grails controller as /cardClient/, i am getting following error:
2019-05-03 18:20:30.333 ERROR --- [nio-8200-exec-1] i.m.retry.intercept.RecoveryInterceptor : Type [grailsmono.NewCardClient$Intercepted] executed with error: Cannot convert publisher into target type: class io.reactivex.Flowable
java.lang.UnsupportedOperationException: Cannot convert publisher into target type: class io.reactivex.Flowable
at io.micronaut.cache.interceptor.CacheInterceptor.interceptPublisher(CacheInterceptor.java:352)
at io.micronaut.cache.interceptor.CacheInterceptor.intercept(CacheInterceptor.java:120)
at io.micronaut.aop.MethodInterceptor.intercept(MethodInterceptor.java:41)
at io.micronaut.aop.chain.InterceptorChain.proceed(InterceptorChain.java:155)
at io.micronaut.discovery.client.$CachingCompositeDiscoveryClientDefinition$Intercepted.getInstances(Unknown Source)
at io.micronaut.discovery.client.CachingCompositeDiscoveryClient.getInstances(CachingCompositeDiscoveryClient.java:38)
at io.micronaut.http.client.loadbalance.DiscoveryClientRoundRobinLoadBalancer.select(DiscoveryClientRoundRobinLoadBalancer.java:58)
at io.micronaut.http.client.DefaultHttpClient.resolveRequestURI(DefaultHttpClient.java:720)
at io.micronaut.http.client.DefaultHttpClient.exchange(DefaultHttpClient.java:410)
at io.micronaut.http.client.DefaultHttpClient.exchange(DefaultHttpClient.java:154)
at io.micronaut.http.client.HttpClient.retrieve(HttpClient.java:125)
at io.micronaut.http.client.RxHttpClient.retrieve(RxHttpClient.java:60)
at io.micronaut.http.client.RxHttpClient.retrieve(RxHttpClient.java:33)
at io.micronaut.http.client.interceptor.HttpClientIntroductionAdvice.intercept(HttpClientIntroductionAdvice.java:331)
at io.micronaut.aop.MethodInterceptor.intercept(MethodInterceptor.java:41)
at io.micronaut.aop.chain.InterceptorChain.proceed(InterceptorChain.java:155)
at io.micronaut.retry.intercept.RecoveryInterceptor.intercept(RecoveryInterceptor.java:74)
at io.micronaut.aop.MethodInterceptor.intercept(MethodInterceptor.java:41)
at io.micronaut.aop.chain.InterceptorChain.proceed(InterceptorChain.java:155)
at grailsmono.NewCardClient$Intercepted.getCards(Unknown Source)
...
Couldn't connect to consul and not able to debug the cause. Please help!!!
With the help of #JeffScottBrown, my workaround got simple just by changing the dependencies version of each as follows :
Added mavenCentral() repository as dependency :
repositories {
mavenLocal()
mavenCentral()
maven { url "https://repo.grails.org/grails/core" }
}
and the required micronaut dependencies as follows :
compile 'io.micronaut:micronaut-inject-java:1.1.0'
compile 'io.micronaut:micronaut-discovery-client:1.1.0'
compile 'io.micronaut:micronaut-spring:1.1.0'
runtime 'io.micronaut:micronaut-runtime:1.1.0'
I have a Spring Boot application which use swagger-ui to expose it's apis.
Now, till I was using springfox-swagger-ui version 2.6.1 my code was working properly. But when I updated the version to 2.7.0 it throws an error that ApiInfo method is deprecated. Can anyone tell me an alternative which will modify the existing code as less as possible and successfully run the application with the Info still there in the Swagger UI as description. I'm giving the existing code of swagger config here...
#Configuration
#EnableSwagger2
public class SwaggerConfig {
#Bean
public Docket productApi() {
return new Docket(DocumentationType.SWAGGER_2)
.useDefaultResponseMessages(false)
.select()
.apis(RequestHandlerSelectors.basePackage("com.xyz.abc"))
.paths(regex("/api.*"))
.build()
.apiInfo(apiInfo());
}
private ApiInfo apiInfo() {
return new ApiInfo(
"My-Project Api",
"Api for My Project",
"V1",
"NA terms of service url",
new Contact("Team Name", "www.somexyzteamcontact.com, "NA"),
"A license given",
"NA");
}
}
And gradle dependency for swagger which I used in My Project:
compile group: 'io.springfox', name: 'springfox-swagger2', version: '2.7.0'
compile group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.7.0'
Try the following, using ApiInfoBuilder to build API
private ApiInfo apiInfo() {
return new ApiInfoBuilder().title("API Reference").version("1.0.0")
.description("something")
.build();
}
This is a pretty confusing one. I've read dozens of links that purport to explain how to use #Transactional but I've verified no transaction is being created.
Main.java
#SpringBootApplication
#EnableJpaRepositories(basePackages="com.mypackage")
#EnableTransactionManagement
#EntityScan(basePackages=["com.mypackage"])
#EnableJpaAuditing
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}
SubscriptionController.java
#RequestMapping("/api/subscription")
#RestController
public class SubscriptionController {
#Autowired SubscriptionService subscriptionService;
Logger log = LogManager.getLogger(this.getClass().getName());
public Collection<Subscriptions> subscribe(...) {
log.info("transName: " + TransactionSynchronizationManager.getCurrentTransactionName + ", isAlive: " + TransactionSynchronizationManager.isActualTransactionActive());
return subscriptionService.getAllSubscriptions();
}
}
SubscriptionService.java
#Service
public class SubscriptionService {
#Transactional public Collection<Subscription> getAllSubscriptions() {
log.info("transName: " + TransactionSynchronizationManager.getCurrentTransactionName() + ", isAlive: " + TransactionSynchronizationManager.isActualTransactionActive());
//return subscriptions via JPQL queries here
}
}
build.gradle
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.0.RELEASE")
}
}
plugins {
id 'war'
}
apply plugin: 'org.springframework.boot'
repositories {
mavenCentral()
}
def springVersion = '5.0.3.RELEASE'
dependencies {
compile 'org.codehaus.groovy:groovy-all:2.3.11'
testCompile group: 'junit', name: 'junit', version: '4.12'
compile "org.springframework.security:spring-security-core:${springVersion}", exclude
compile "org.springframework.security:spring-security-config:${springVersion}", exclude
compile "org.springframework.security:spring-security-web:${springVersion}", exclude
testCompile group: 'junit', name: 'junit', version: '4.12'
testCompile "org.springframework:spring-test:${springVersion}", exclude
implementation 'org.springframework.boot:spring-boot-starter-web:2.0.5.RELEASE', exclude
compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa', version: '2.0.5.RELEASE'
compile group: 'mysql', name: 'mysql-connector-java', version: '8.0.11'
compile 'org.liquibase:liquibase-core:3.6.1'
compile 'org.liquibase:liquibase-groovy-dsl:1.2.2'
}
So when I run the api call, I get null, false as the log output. The contract for #Transactional says that the transactional aspect code will be weaved into the annotated transactional method, such that there will be a transaction (and thus an entitymanager and db connection) set up before the method and closed some time afterward. But that is irrelevant becuase shouldn't spring be creating an entitymanager before the controller is run? Both things aren't working here. Neither spring, nor #Transactional, is setting up any transaction. This results in failure to do any kind of query except for what's doable via a subclasses of JpaRepository. Somehow my Jpa repositories are able to set up transactions for their own methods. But what if their results have lazily initialized properties? I need a hibernate session to get those. So I need a transaction.
Try to remove
#EnableJpaRepositories(basePackages="com.mypackage")
#EnableTransactionManagement
SpringBoot should do those things automatically
What class are you using for #Transactional?
You should use org.springframework.transaction.annotation.Transactional.
An out-of-the-box Spring-boot application using spring initializer (https://start.spring.io/) will handle transactions properly. If you make yourself a sandbox with a unit test you can observer that the transaction demarcation done in your example will produce a transaction. Here is my git hub example: https://github.com/skjenco/hibernateSandbox.git
Code:
#Test
#Transactional
public void test() {
logger.info(TransactionSynchronizationManager.getCurrentTransactionName());
.....
For transaction demarcation to work you must be in an object managed by a Spring (Component, Service, Managed Beans, etc). In the case above it appears that you are in a Spring managed service. Using a working sandbox may be helpful in trouble shooting your issue--that is what I have done to solve perplexing hibernate issues.
You may also want to post your pom.xml file. spring-data or spring-tx dependency should be added for auto configurer to create transaction manager. Otherwise explicitly create a transaction manager bean and run the code again.
You can enable TRACE level logs for org.springframework and see if transaction manager is initialized.
Also check transaction interceptor logs. Use logging.level.org.springframework.transaction.interceptor=TRACE