RockteMQ-AI commented on code in PR #87:
URL: https://github.com/apache/rocketmq-operator/pull/87#discussion_r3902449693
##########
pkg/controller/broker/broker_controller.go:
##########
@@ -104,6 +105,43 @@ type ReconcileBroker struct {
scheme *runtime.Scheme
}
+func (r *ReconcileBroker) CreateService(request reconcile.Request, broker
*rocketmqv1alpha1.Broker, brokerGroupIndex int, replicaIndex int) {
+ reqLogger := log.WithValues("Request.Namespace", request.Namespace,
"Request.Name", request.Name)
+ reqLogger.Info("Create a Broker Service...")
+
+ svc := r.getBrokerService(broker, brokerGroupIndex, replicaIndex)
+ svcObj := &corev1.Service{}
+ err := r.client.Get(context.TODO(), types.NamespacedName{Name:
svc.Name, Namespace: svc.Namespace}, svcObj)
+ if err != nil && errors.IsNotFound(err) {
+ reqLogger.Info("Creating a Broker Service.",
"Service.Namespace", svc.Namespace, "Service.Name", svc.Name)
+ err = r.client.Create(context.TODO(), svc)
+ if err != nil {
+ reqLogger.Error(err, "Failed to create new Service",
"Service.Namespace", svc.Namespace, "Service.Name", svc.Name)
+ }
+ } else if err != nil {
+ reqLogger.Error(err, "Failed to get Broker Service.")
+ }
+}
+
+func (r *ReconcileBroker) DLegerHostIp(request reconcile.Request, broker
*rocketmqv1alpha1.Broker, brokerGroupIndex int, replicaIndex int) string {
+ reqLogger := log.WithValues("Request.Namespace", request.Namespace,
"Request.Name", request.Name)
+ reqLogger.Info("Get DLeger Host IP lists...")
+
+ statefulSetName := getBrokerStatefulSetName(broker, brokerGroupIndex,
replicaIndex)
+
Review Comment:
`DLegerHostIp` contains an unbounded `for {}` loop with `time.Sleep` that
polls forever until the Service exists. This blocks the reconcile goroutine
indefinitely if the Service creation failed (e.g., RBAC denial, quota
exceeded). The controller will deadlock — no other reconcile events can be
processed on this worker. Replace with a bounded retry or, better, return the
error from Reconcile and let the controller framework requeue with backoff.
##########
pkg/controller/broker/broker_controller.go:
##########
@@ -104,6 +105,43 @@ type ReconcileBroker struct {
scheme *runtime.Scheme
}
+func (r *ReconcileBroker) CreateService(request reconcile.Request, broker
*rocketmqv1alpha1.Broker, brokerGroupIndex int, replicaIndex int) {
Review Comment:
`CreateService` logs the error from `r.client.Create` but does not return
it. The caller proceeds to build a StatefulSet and call `DLegerHostIp` which
will then block forever waiting for the Service that failed to create. This
should return an `error` to the caller so Reconcile can requeue.
##########
pkg/controller/broker/broker_controller.go:
##########
@@ -154,9 +192,18 @@ func (r *ReconcileBroker) Reconcile(request
reconcile.Request) (reconcile.Result
share.BrokerClusterName = broker.Name
replicaPerGroup := broker.Spec.ReplicaPerGroup
reqLogger.Info("brokerGroupNum=" + strconv.Itoa(share.GroupNum) + ",
replicaPerGroup=" + strconv.Itoa(replicaPerGroup))
+
for brokerGroupIndex := 0; brokerGroupIndex < share.GroupNum;
brokerGroupIndex++ {
Review Comment:
DLeger peer construction and `CreateService`/`DLegerHostIp` calls are
unconditional — they run even when `broker.Spec.EnableDLeger` is `false`. This
creates unnecessary Services and blocks on them for every non-DLedger
deployment. Wrap the DLeger-specific logic in an `if broker.Spec.EnableDLeger`
guard.
##########
pkg/controller/nameservice/nameservice_controller.go:
##########
@@ -157,9 +158,18 @@ func (r *ReconcileNameService) Reconcile(request
reconcile.Request) (reconcile.R
return r.updateNameServiceStatus(instance, request, true)
}
+func getNameServiceName(nameService *rocketmqv1alpha1.NameService) string {
Review Comment:
`getNameServiceName` panics when `nameService.Spec.Size` is 0: the loop body
never executes, `nameserviceName` remains `""`, and
`nameserviceName[:len(nameserviceName)-1]` evaluates to `""[:-1]` which is an
out-of-bounds slice. Add a guard for `Size == 0`.
##########
pkg/share/share.go:
##########
@@ -25,6 +25,9 @@ var (
// NameServersStr is the name server list
NameServersStr = ""
+ // NameServersStr is the name server list
Review Comment:
`NameServersServiceStr` is a package-level mutable global written by the
NameService controller (`nameservice_controller.go:168`) and read by the Broker
controller (`broker_controller.go:575`). This is a data race in a concurrent
controller-runtime environment where both reconcilers run in parallel
goroutines. Use a thread-safe mechanism (mutex, or pass via CR status) instead
of a bare global string.
##########
pkg/apis/rocketmq/v1alpha1/broker_types.go:
##########
@@ -34,14 +34,18 @@ type BrokerSpec struct {
Size int `json:"size"`
// NameServers defines the name service list e.g.
192.168.1.1:9876;192.168.1.2:9876
NameServers string `json:"nameServers,omitempty"`
+ // Whether enable rocketmq-on-dleger group deploy, false in default
+ EnableDLeger bool `json:"enableDLeger"`
// ReplicaPerGroup each broker cluster's replica number
ReplicaPerGroup int `json:"replicaPerGroup"`
// BaseImage is the broker image to use for the Pods
BrokerImage string `json:"brokerImage"`
// ImagePullPolicy defines how the image is pulled
ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy"`
// AllowRestart defines whether allow pod restart
- AllowRestart bool `json:"allowRestart"`
+ AllowRestart bool `json:"allowRestart"`
+ Affinity corev1.Affinity `json:"affinity"`
Review Comment:
`Tolerations` and other new fields (`Env` in NameService) also lack
`omitempty` in their JSON tags. This forces users to provide empty arrays in
their CRs and makes the CRD schema unnecessarily strict.
##########
pkg/apis/rocketmq/v1alpha1/broker_types.go:
##########
@@ -34,14 +34,18 @@ type BrokerSpec struct {
Size int `json:"size"`
// NameServers defines the name service list e.g.
192.168.1.1:9876;192.168.1.2:9876
NameServers string `json:"nameServers,omitempty"`
+ // Whether enable rocketmq-on-dleger group deploy, false in default
+ EnableDLeger bool `json:"enableDLeger"`
// ReplicaPerGroup each broker cluster's replica number
ReplicaPerGroup int `json:"replicaPerGroup"`
// BaseImage is the broker image to use for the Pods
BrokerImage string `json:"brokerImage"`
// ImagePullPolicy defines how the image is pulled
ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy"`
// AllowRestart defines whether allow pod restart
- AllowRestart bool `json:"allowRestart"`
+ AllowRestart bool `json:"allowRestart"`
Review Comment:
`Affinity` is declared as `corev1.Affinity` (value type) without
`omitempty`. An empty Affinity struct will always be serialized into the
StatefulSet pod spec even when the user sets none, and the CRD makes it
required. Use `*corev1.Affinity` (pointer) with `json:"affinity,omitempty"` so
it is nil when unset.
##########
pkg/controller/broker/broker_controller.go:
##########
@@ -104,6 +105,43 @@ type ReconcileBroker struct {
scheme *runtime.Scheme
}
+func (r *ReconcileBroker) CreateService(request reconcile.Request, broker
*rocketmqv1alpha1.Broker, brokerGroupIndex int, replicaIndex int) {
+ reqLogger := log.WithValues("Request.Namespace", request.Namespace,
"Request.Name", request.Name)
+ reqLogger.Info("Create a Broker Service...")
+
+ svc := r.getBrokerService(broker, brokerGroupIndex, replicaIndex)
+ svcObj := &corev1.Service{}
+ err := r.client.Get(context.TODO(), types.NamespacedName{Name:
svc.Name, Namespace: svc.Namespace}, svcObj)
+ if err != nil && errors.IsNotFound(err) {
+ reqLogger.Info("Creating a Broker Service.",
"Service.Namespace", svc.Namespace, "Service.Name", svc.Name)
+ err = r.client.Create(context.TODO(), svc)
+ if err != nil {
+ reqLogger.Error(err, "Failed to create new Service",
"Service.Namespace", svc.Namespace, "Service.Name", svc.Name)
+ }
+ } else if err != nil {
+ reqLogger.Error(err, "Failed to get Broker Service.")
+ }
+}
+
+func (r *ReconcileBroker) DLegerHostIp(request reconcile.Request, broker
*rocketmqv1alpha1.Broker, brokerGroupIndex int, replicaIndex int) string {
+ reqLogger := log.WithValues("Request.Namespace", request.Namespace,
"Request.Name", request.Name)
+ reqLogger.Info("Get DLeger Host IP lists...")
+
+ statefulSetName := getBrokerStatefulSetName(broker, brokerGroupIndex,
replicaIndex)
+
+ svcObj := &corev1.Service{}
+ for {
+ err := r.client.Get(context.TODO(), types.NamespacedName{Name:
statefulSetName, Namespace: broker.Namespace}, svcObj)
+ if err != nil && errors.IsNotFound(err) {
+ log.Info("Waiting for broker service created...")
+
time.Sleep(time.Duration(cons.WaitForNameServerReadyInSecond) * time.Second)
Review Comment:
`DLegerHostIp` returns `svcObj.Spec.ClusterIP` from a Service that may have
just been created. For non-headless Services (the broker services here have no
`ClusterIP: "None"`), the ClusterIP is assigned asynchronously by the API
server. A tight poll loop may read an empty ClusterIP. Consider using a
headless Service + pod DNS (e.g., `<pod>.<svc>.<ns>.svc.cluster.local`) for
stable addressing.
##########
pkg/controller/console/console_controller.go:
##########
@@ -200,12 +195,12 @@ func newDeploymentForCR(cr *rocketmqv1alpha1.Console)
*appsv1.Deployment {
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{{
- Resources:
cr.Spec.ConsoleDeployment.Spec.Template.Spec.Containers[0].Resources,
- Image:
cr.Spec.ConsoleDeployment.Spec.Template.Spec.Containers[0].Image,
- Name:
cr.Spec.ConsoleDeployment.Spec.Template.Spec.Containers[0].Name,
+ Resources:
cr.Spec.ConsoleDeployment.Spec.Template.Spec.Containers[0].Resources,
Review Comment:
The hardcoded `JAVA_OPTS` env var (containing `-Drocketmq.namesrv.addr=...`)
was removed without a replacement mechanism. Users who relied on the operator
injecting the name server address into the console will now get a console that
cannot connect to RocketMQ. The example CRs add `JAVA_OPTS` manually, but
existing deployments that upgrade will silently break. Consider keeping a
default or documenting this as a breaking change.
##########
deploy/crds/rocketmq_v1alpha1_broker_crd.yaml:
##########
@@ -95,24 +841,26 @@ spec:
type: object
type: array
required:
Review Comment:
`enableDLeger` is added to the `required` fields list. This is a breaking
change — any existing Broker CR that does not specify `enableDLeger` will be
rejected by the API server on update. New optional fields should not be
required; rely on the Go zero-value (`false`) or add a default via admission
webhook.
##########
images/broker/alpine/brokerGenConfig.sh:
##########
@@ -30,6 +30,17 @@ function create_config() {
if [ $BROKER_ID != 0 ]; then
sed -i 's/brokerRole=.*/brokerRole=SLAVE/g' $BROKER_CONFIG_FILE
fi
+
+ # Enable RocketMQ-on-DLedger Group
Review Comment:
The shell test `[ ! -z $ENABLE_DLEGER ]` is unquoted. If `ENABLE_DLEGER` is
unset (not just empty), this becomes `[ ! -z ]` which evaluates to true (tests
the `-z` flag itself as a non-empty string), enabling DLedger unintentionally.
Quote it: `[ ! -z "$ENABLE_DLEGER" ]` or use `[ -n "$ENABLE_DLEGER" ]`.
##########
pkg/controller/nameservice/nameservice_controller.go:
##########
@@ -301,7 +311,53 @@ func labelsForNameService(name string) map[string]string {
return map[string]string{"app": "name_service", "name_service_cr": name}
}
+func (r *ReconcileNameService) getNameServiceService(nameService
*rocketmqv1alpha1.NameService) *corev1.Service {
+ statefulSetName := nameService.Name
+ ls := labelsForNameService(nameService.Name)
+
+ svc := &corev1.Service{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: statefulSetName,
+ Labels: ls,
+ Namespace: nameService.Namespace,
+ },
+ Spec: corev1.ServiceSpec{
+ Selector: ls,
+ ClusterIP: "None",
+ Ports: []corev1.ServicePort{{
+ Name:
cons.NameServiceMainContainerPortName,
+ Port: cons.NameServiceMainContainerPort,
+ TargetPort:
intstr.FromInt(cons.NameServiceMainContainerPort),
+ }},
+ },
+ }
+
+ // Set bind for broker crd and svc
+ controllerutil.SetControllerReference(nameService, svc, r.scheme)
+
+ return svc
+}
+
+func (r *ReconcileNameService) CreateService(request reconcile.Request,
nameService *rocketmqv1alpha1.NameService) {
+ reqLogger := log.WithValues("Request.Namespace", request.Namespace,
"Request.Name", request.Name)
+ reqLogger.Info("Create a Name Service...")
+
Review Comment:
The comment says `// Set bind for broker crd and svc` but this is in the
NameService controller and the owner reference is set to `nameService`, not a
broker. Copy-paste artifact — update the comment to reflect the actual owner.
##########
pkg/controller/broker/broker_controller.go:
##########
@@ -453,10 +569,10 @@ func (r *ReconcileBroker) getBrokerStatefulSet(broker
*rocketmqv1alpha1.Broker,
}
Review Comment:
`share.NameServersStr` was replaced with `share.NameServersServiceStr` in
the broker env. `NameServersServiceStr` is built from the CR name and assumes a
specific headless service naming convention. If the NameService controller
hasn't reconciled yet, this value may be stale or empty, causing brokers to
start with no valid name server address.
##########
pkg/controller/broker/broker_controller.go:
##########
@@ -193,8 +241,14 @@ func (r *ReconcileBroker) Reconcile(request
reconcile.Request) (reconcile.Result
for brokerGroupIndex := 0; brokerGroupIndex <
broker.Spec.Size; brokerGroupIndex++ {
Review Comment:
In the scale-down/update path, `CreateService` is called for replicas inside
the nameServers-update loop but never for the master (replicaIndex 0). If the
master's Service was deleted externally, it will not be recreated during
updates, while replica services will be. This is inconsistent with the initial
creation path at line 196.
##########
pkg/share/share.go:
##########
@@ -25,6 +25,9 @@ var (
// NameServersStr is the name server list
NameServersStr = ""
+ // NameServersStr is the name server list
Review Comment:
The comment on `NameServersServiceStr` says `// NameServersStr is the name
server list` — it's a copy of the comment above it. Update to describe what
this variable actually holds (service-based name server addresses).
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]