Repository: kedacore/keda

Issue:
`cron_scaler` always reports 1 when inactive, preventing zero scaling with `scalingModifiers`
This issue is a continuation of the discussion previously seen in this [GitHub comment](https://github.com/kedacore/keda/issues/5078#issuecomment-1766356660), which highlighted problems with ScaledObject and multiple triggers.

### The Problem

The cron_scaler prevents true zero scaling when used with scalingModifiers even if minReplicaCount is 0. This happens because the cron_scaler always reports a metric value of 1 during its inactive periods. This means scalingModifiers (e.g., formula: `X * cron_scaler`) can't result in 0.

### Root Cause

The core issue lies in the GetMetricsAndActivity function within cron_scaler.go. The metricValue is initialized to 1 and remains 1 if the cron schedule is inactive, regardless of the desired replica count.

```go
// Excerpt from pkg/scalers/cron_scaler.go
func (s *cronScaler) GetMetricsAndActivity(...) {
    // ...
    metricValue := float64(1) // This is the core issue
    // ...
}
```

### Expected Behavior

When the cron_scaler's defined schedule is inactive, and minReplicaCount is 0, the ScaledObject should scale down to 0 replicas. This would imply that the cron_scaler reports a metric value of 0 (or effectively 0) during its inactive period, allowing scalingModifiers with a multiplication formula (e.g., `X * cron_scaler`) to result in 0.

### Actual Behavior

The ScaledObject does not scale down to 0, even when the cron schedule is inactive and minReplicaCount is set to 0. Instead, the deployment maintains at least 1 replica (or the minReplicaCount if higher than 0 but still not 0). This is because the external_metrics for the cron_scaler consistently reports 1 during its inactive periods, causing scalingModifiers to yield a non-zero result.

### Steps to Reproduce the Problem

1.Prepare a Deployment: Ensure you have a Kubernetes Deployment named exampl-server (or modify the ScaledObject below to point to your deployment). This deployment should ideally be able to scale down to 0.
2.Apply the ScaledObject: Deploy the following ScaledObject configuration to your cluster:

```yaml
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: example
  namespace: example
spec:
  scaleTargetRef:
    name: exampl-server
  minReplicaCount: 0
  maxReplicaCount: 4
  cooldownPeriod: 0
  advanced:
    scalingModifiers:
      formula: "1 * cron_scaler"
      target: "1"
  triggers:
    - type: cron
      name: cron_scaler
      metadata:
        timezone: Asia/Tokyo
        start: 00 6 * * 1-5 # Active from 6 AM to 1 PM JST, Monday-Friday
        end: 00 13 * * 1-5
        desiredReplicas: "1"
```

3. Observe the exampl-server deployment's replica count outside the active cron schedule (e.g., after 1 PM JST on a weekday, or any time on a Saturday/Sunday).


### Logs from KEDA operator

```
example
```


### KEDA Version

v2.17.2

### Kubernetes Version

v1.32

### Platform

None

### Scaler Details

_No response_

### Anything else?

_No response_

Discussion:
@frauniki: I think if I set the default metric of the cron scaler to zero, this problem will go away.
```go
// Excerpt from pkg/scalers/cron_scaler.go
func (s *cronScaler) GetMetricsAndActivity(...) {
    // ...
    metricValue := float64(0) // <--
    // ...
}
```
But now it is not set to zero. Is there some particular reason I am unaware of?@rickbrouwer: Hi!

I've done some testing and I think it's fine to set the `metricValue` to `float64(0)`.

Is that something you'd like to contribute yourself?
If that doesn't work, please let me know. No rush :)@frauniki: > Hi!
> 
> I've done some testing and I think it's fine to set the `metricValue` to `float64(0)`.
> 
> Is that something you'd like to contribute yourself? If that doesn't work, please let me know. No rush :)

Hi!

I will try to work on that fix.
Thank you very much:)

Solution patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 951160020..52904c572 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -63,8 +63,8 @@ To learn more about active deprecations, we recommend checking [GitHub Discussio
 
 ### New
 
+- **General**: Enable support on s390x for KEDA ([#6543](https://github.com/kedacore/keda/issues/6543))
 - **General**: Introduce new Solace Direct Messaging scaler ([#6545](https://github.com/kedacore/keda/issues/6545))
-- Enable support on s390x for KEDA ([#6543](https://github.com/kedacore/keda/issues/6543))
 - **General**: Introduce new Sumo Logic Scaler ([#6734](https://github.com/kedacore/keda/issues/6734))
 
 #### Experimental
@@ -85,7 +85,8 @@ To learn more about active deprecations, we recommend checking [GitHub Discussio
 - **General**: Fix prefixes on envFrom elements in a deployment spec aren't being interpreted and Environment variables are not prefixed with the prefix ([#6728](https://github.com/kedacore/keda/issues/6728))
 - **General**: Remove klogr dependency and replace with zap ([#5732](https://github.com/kedacore/keda/issues/5732))
 - **General**: Sets hpaName in Status when ScaledObject adopts/finds an existing HPA ([#6336](https://github.com/kedacore/keda/issues/6336))
-- **RabbitMQ**: Fix incorrect URL encoding in RabbitMQ vhosts containing %2f ([#6963](https://github.com/kedacore/keda/issues/6963))
+- **Cron Scaler**: Fix cron scaler to return zero metric value by default([#6886](https://github.com/kedacore/keda/issues/6886))
+- **RabbitMQ Scaler**: Fix incorrect URL encoding in RabbitMQ vhosts containing %2f ([#6963](https://github.com/kedacore/keda/issues/6963))
 
 ### Deprecations
 
diff --git a/pkg/scalers/cron_scaler.go b/pkg/scalers/cron_scaler.go
index 8cf4c35ba..61c018fee 100644
--- a/pkg/scalers/cron_scaler.go
+++ b/pkg/scalers/cron_scaler.go
@@ -141,7 +141,7 @@ func (s *cronScaler) GetMetricsAndActivity(_ context.Context, metricName string)
 		isWithinInterval = currentTime.After(nextStartTime) || currentTime.Before(nextEndTime)
 	}
 
-	metricValue := float64(1)
+	metricValue := float64(0)
 	if isWithinInterval {
 		metricValue = float64(s.metadata.DesiredReplicas)
 	}



Test patch:
diff --git a/pkg/scalers/cron_scaler_test.go b/pkg/scalers/cron_scaler_test.go
index d0b67ec2b..2fdd24240 100644
--- a/pkg/scalers/cron_scaler_test.go
+++ b/pkg/scalers/cron_scaler_test.go
@@ -101,7 +101,7 @@ func TestGetMetrics(t *testing.T) {
 	if currentDay == "Thursday" {
 		assert.Equal(t, metrics[0].Value.Value(), int64(10))
 	} else {
-		assert.Equal(t, metrics[0].Value.Value(), int64(1))
+		assert.Equal(t, metrics[0].Value.Value(), int64(0))
 	}
 }
 
@@ -112,7 +112,7 @@ func TestGetMetricsRange(t *testing.T) {
 	if currentHour%2 == 0 {
 		assert.Equal(t, metrics[0].Value.Value(), int64(10))
 	} else {
-		assert.Equal(t, metrics[0].Value.Value(), int64(1))
+		assert.Equal(t, metrics[0].Value.Value(), int64(0))
 	}
 }