multiple source calculation

This commit is contained in:
Ali Sadeghi
2025-08-04 18:26:36 +03:30
parent 09933c8bbf
commit 831eab906b
7 changed files with 812 additions and 496 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -2,8 +2,13 @@ package com.sgs.graphql.dataCenter.domain;
import com.fasterxml.jackson.annotation.JsonBackReference; import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonManagedReference; import com.fasterxml.jackson.annotation.JsonManagedReference;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sgs.lib.dao.domain.BaseDomain; import com.sgs.lib.dao.domain.BaseDomain;
import java.util.Map;
import java.util.HashMap;
import javax.persistence.*; import javax.persistence.*;
@Entity @Entity
@@ -18,9 +23,11 @@ public class VM extends BaseDomain {
private String host; private String host;
private String flavorName; private String flavorName;
private String tag; private String tag;
private String emissionSourceData; // JSON string to store emission source map
private Config config; private Config config;
private PhysicalMachine physicalMachine; private PhysicalMachine physicalMachine;
@Column(name = "state") @Column(name = "state")
public String getState() { public String getState() {
return state; return state;
@@ -102,6 +109,15 @@ public class VM extends BaseDomain {
this.ip = ip; this.ip = ip;
} }
@Column(name = "emission_source_data", columnDefinition = "text")
public String getEmissionSourceData() {
return emissionSourceData;
}
public void setEmissionSourceData(String emissionSourceData) {
this.emissionSourceData = emissionSourceData;
}
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "vm") @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "vm")
@JsonManagedReference @JsonManagedReference
public Config getConfig() { public Config getConfig() {
@@ -123,4 +139,33 @@ public class VM extends BaseDomain {
this.physicalMachine = physicalMachine; this.physicalMachine = physicalMachine;
} }
// Helper methods for emission source map
@Transient
public Map<String, Integer> getEmissionSource() {
if (emissionSourceData == null || emissionSourceData.trim().isEmpty()) {
return new HashMap<>();
}
try {
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(emissionSourceData, new TypeReference<Map<String, Integer>>() {});
} catch (Exception e) {
System.err.println("Error parsing emission source data: " + e.getMessage());
return new HashMap<>();
}
}
public void setEmissionSource(Map<String, Integer> emissionSource) {
if (emissionSource == null) {
this.emissionSourceData = null;
return;
}
try {
ObjectMapper mapper = new ObjectMapper();
this.emissionSourceData = mapper.writeValueAsString(emissionSource);
} catch (Exception e) {
System.err.println("Error serializing emission source data: " + e.getMessage());
this.emissionSourceData = null;
}
}
} }

View File

@@ -2,6 +2,7 @@ package com.sgs.graphql.dataCenter.dto;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List; import java.util.List;
import java.util.Map;
public class VMDto { public class VMDto {
@JsonProperty("vm_name") @JsonProperty("vm_name")
@@ -28,6 +29,9 @@ public class VMDto {
@JsonProperty("confg") // Note: keeping the typo from JSON @JsonProperty("confg") // Note: keeping the typo from JSON
private List<Object> confg; private List<Object> confg;
@JsonProperty("emissionsource")
private Map<String, Integer> emissionSource;
private String ip; // IP address from the message key private String ip; // IP address from the message key
private boolean calcOn = false; // Derived from state: active = true, inactive = false private boolean calcOn = false; // Derived from state: active = true, inactive = false
@@ -113,6 +117,14 @@ public class VMDto {
this.calcOn = calcOn; this.calcOn = calcOn;
} }
public Map<String, Integer> getEmissionSource() {
return emissionSource;
}
public void setEmissionSource(Map<String, Integer> emissionSource) {
this.emissionSource = emissionSource;
}
// Helper method to get config as ConfigDto // Helper method to get config as ConfigDto
public ConfigDto getConfig() { public ConfigDto getConfig() {
if (confg != null && confg.size() >= 5) { if (confg != null && confg.size() >= 5) {

View File

@@ -92,7 +92,14 @@ public class MessageListener {
DataCenter entity = toDataCenterEntity(dto); DataCenter entity = toDataCenterEntity(dto);
DataCenter dataCenter = createDataCenter(entity); DataCenter dataCenter = createDataCenter(entity);
processEmissionCalculations(dataCenter);
// Save message processing success log
systemLogger.createSystemLog(LogType.INFO,
"VM data processed successfully for DataCenter ID: " + dataCenter.getExternalId());
// Process emission calculations in a separate transaction to avoid rollback issues
// This will be done asynchronously after the VM data is committed
processEmissionCalculationsAsync(dataCenter);
// System.out.println(entity.toString()); // System.out.println(entity.toString());
System.out.println("✅ Raw JSON message:\n" + message); System.out.println("✅ Raw JSON message:\n" + message);
@@ -117,7 +124,11 @@ public class MessageListener {
//System.out.println("✅ Saved DataCenter:\n" + objectMapper.writeValueAsString(dataCenter)); //System.out.println("✅ Saved DataCenter:\n" + objectMapper.writeValueAsString(dataCenter));
} catch (Exception e) { } catch (Exception e) {
System.err.println("Mesaj işlenirken hata oluştu: " + e.getMessage()); System.err.println("Mesaj işlenirken hata oluştu: " + e.getMessage());
e.printStackTrace();
systemLogger.createSystemLog(LogType.ERROR,
"Error processing VM message: " + e.getMessage());
// Don't rethrow the exception to prevent transaction rollback
} }
} }
@@ -153,8 +164,14 @@ public class MessageListener {
// Handle config from confg array // Handle config from confg array
entity.setConfig(toConfigEntity(dto.getConfig())); entity.setConfig(toConfigEntity(dto.getConfig()));
// Handle emission source map
entity.setEmissionSource(dto.getEmissionSource());
// Debug logging // Debug logging
System.out.println("🔍 VM Entity Created: " + dto.getVmName() + " - state = " + dto.getState() + " - calcOn = " + dto.isCalcOn()); System.out.println("🔍 VM Entity Created: " + dto.getVmName() + " - state = " + dto.getState() + " - calcOn = " + dto.isCalcOn());
if (dto.getEmissionSource() != null && !dto.getEmissionSource().isEmpty()) {
System.out.println(" Emission Sources: " + dto.getEmissionSource());
}
return entity; return entity;
} }
@@ -401,6 +418,7 @@ public class MessageListener {
vm.setHost(newVm.getHost()); vm.setHost(newVm.getHost());
vm.setFlavorName(newVm.getFlavorName()); vm.setFlavorName(newVm.getFlavorName());
vm.setTag(newVm.getTag()); vm.setTag(newVm.getTag());
vm.setEmissionSource(newVm.getEmissionSource());
System.out.println("✅ Updated existing VM: " + vm.getVmName() + " (IP: " + vm.getIp() + ") - calcOn = " + vm.getCalcOn()); System.out.println("✅ Updated existing VM: " + vm.getVmName() + " (IP: " + vm.getIp() + ") - calcOn = " + vm.getCalcOn());
} else { } else {
@@ -450,6 +468,32 @@ public class MessageListener {
} }
/**
* Process emission calculations asynchronously to avoid transaction conflicts
*/
public void processEmissionCalculationsAsync(DataCenter dataCenter) {
// Run emission calculations in a separate thread to avoid transaction issues
new Thread(() -> {
try {
// Wait a bit to ensure the transaction is committed and VMs have IDs
Thread.sleep(2000);
// Refresh the DataCenter to get the latest state with VM IDs
Optional<DataCenter> refreshedDcOpt = dataCenterRepo.findByExternalId(dataCenter.getExternalId());
if (refreshedDcOpt.isPresent()) {
DataCenter refreshedDc = refreshedDcOpt.get();
System.out.println("🔄 Processing emission calculations asynchronously for DataCenter: " + refreshedDc.getDataCenter());
processEmissionCalculations(refreshedDc);
} else {
System.err.println("❌ Could not find DataCenter for emission calculations: " + dataCenter.getExternalId());
}
} catch (Exception e) {
System.err.println("❌ Error in async emission calculations: " + e.getMessage());
e.printStackTrace();
}
}).start();
}
public void processEmissionCalculations(DataCenter dataCenter) { public void processEmissionCalculations(DataCenter dataCenter) {
System.out.println("🔍 Starting VM-level emission calculations for DataCenter ID: " + dataCenter.getId() + System.out.println("🔍 Starting VM-level emission calculations for DataCenter ID: " + dataCenter.getId() +
" (Name: " + dataCenter.getDataCenter() + ")"); " (Name: " + dataCenter.getDataCenter() + ")");
@@ -476,7 +520,10 @@ public class MessageListener {
" (Name: " + dataCenter.getDataCenter() + ")"); " (Name: " + dataCenter.getDataCenter() + ")");
int totalVMs = 0; int totalVMs = 0;
int eligibleVMs = 0; int eligibleVMs = 0;
int processedVMs = 0;
int successfulCalculations = 0; int successfulCalculations = 0;
int failedCalculations = 0;
int totalEmissionSources = 0;
for (Project project : dataCenter.getProjects()) { for (Project project : dataCenter.getProjects()) {
for (PhysicalMachine pm : project.getPhysicalMachines()) { for (PhysicalMachine pm : project.getPhysicalMachines()) {
@@ -488,8 +535,37 @@ public class MessageListener {
eligibleVMs++; eligibleVMs++;
if (vm.getPower() != null && vm.getPower() > 0) { if (vm.getPower() != null && vm.getPower() > 0) {
System.out.println("✅ Processing VM " + vm.getVmName() + " (calcOn = true)"); System.out.println("✅ Processing VM " + vm.getVmName() + " (calcOn = true)");
boolean success = createVMEmissionRecord(dataCenter, vm, project, pm); processedVMs++;
if (success) successfulCalculations++;
// Check if VM has emission sources
Map<String, Integer> emissionSources = vm.getEmissionSource();
if (emissionSources != null && !emissionSources.isEmpty()) {
// Create separate emission record for each emission source
System.out.println("🔍 VM has " + emissionSources.size() + " emission sources");
totalEmissionSources += emissionSources.size();
for (Map.Entry<String, Integer> sourceEntry : emissionSources.entrySet()) {
String sourceName = sourceEntry.getKey();
Integer percentage = sourceEntry.getValue();
System.out.println(" - " + sourceName + ": " + percentage + "%");
boolean success = createVMEmissionRecordForSource(dataCenter, vm, project, pm, sourceName, percentage);
if (success) {
successfulCalculations++;
} else {
failedCalculations++;
}
}
} else {
// Fallback to default emission source if VM has no emission sources
System.out.println("⚠️ VM has no emission sources, using default");
totalEmissionSources++;
boolean success = createVMEmissionRecord(dataCenter, vm, project, pm);
if (success) {
successfulCalculations++;
} else {
failedCalculations++;
}
}
} else { } else {
System.out.println("⚠️ Skipping VM " + vm.getVmName() + " (calcOn = true) - no power consumption data"); System.out.println("⚠️ Skipping VM " + vm.getVmName() + " (calcOn = true) - no power consumption data");
} }
@@ -504,13 +580,21 @@ public class MessageListener {
System.out.println("🎯 VM Emission Calculation Summary:"); System.out.println("🎯 VM Emission Calculation Summary:");
System.out.println(" Total VMs found: " + totalVMs); System.out.println(" Total VMs found: " + totalVMs);
System.out.println(" VMs with calcOn = true: " + eligibleVMs); System.out.println(" VMs with calcOn = true: " + eligibleVMs);
System.out.println(" VMs processed for emissions: " + processedVMs);
System.out.println(" VMs skipped (calcOn = false or null): " + (totalVMs - eligibleVMs)); System.out.println(" VMs skipped (calcOn = false or null): " + (totalVMs - eligibleVMs));
System.out.println(" Total emission source calculations: " + totalEmissionSources);
System.out.println(" Successful emission calculations: " + successfulCalculations); System.out.println(" Successful emission calculations: " + successfulCalculations);
System.out.println(" Failed calculations: " + (eligibleVMs - successfulCalculations)); System.out.println(" Failed emission calculations: " + failedCalculations);
} }
private boolean createVMEmissionRecord(DataCenter dataCenter, VM vm, Project project, PhysicalMachine pm) { private boolean createVMEmissionRecord(DataCenter dataCenter, VM vm, Project project, PhysicalMachine pm) {
try { try {
// Check if VM has an ID (is persisted)
if (vm.getId() == null) {
System.err.println("❌ VM " + vm.getVmName() + " has no ID - cannot create emission record");
return false;
}
MainDataTableCreateInput input = createVMMainDataTableInput(dataCenter, vm, project, pm); MainDataTableCreateInput input = createVMMainDataTableInput(dataCenter, vm, project, pm);
System.out.println("🔍 Creating emission record for VM: " + vm.getVmName() + " (Power: " + vm.getPower() + "W)"); System.out.println("🔍 Creating emission record for VM: " + vm.getVmName() + " (Power: " + vm.getPower() + "W)");
@@ -535,6 +619,52 @@ public class MessageListener {
} }
} }
private boolean createVMEmissionRecordForSource(DataCenter dataCenter, VM vm, Project project, PhysicalMachine pm, String emissionSourceName, Integer percentage) {
try {
// Check if VM has an ID (is persisted)
if (vm.getId() == null) {
System.err.println("❌ VM " + vm.getVmName() + " has no ID - cannot create emission record for source " + emissionSourceName);
return false;
}
// Find the emission source by name/tag
List<EmissionSource> emissionSources = emissionSourceRepo.findByTag(emissionSourceName);
if (emissionSources.isEmpty()) {
System.err.println("❌ Could not find emission source: " + emissionSourceName);
return false;
}
EmissionSource emissionSource = emissionSources.get(0);
// Calculate power consumption for this emission source (percentage of total VM power)
double sourceSpecificPower = vm.getPower() * (percentage / 100.0);
MainDataTableCreateInput input = createVMMainDataTableInputForSource(dataCenter, vm, project, pm, emissionSource, sourceSpecificPower, percentage);
System.out.println("🔍 Creating emission record for VM: " + vm.getVmName() +
" - Source: " + emissionSourceName + " (" + percentage + "%) - Power: " + sourceSpecificPower + "W");
MainDataTable result = callMainDataTableMutation(input);
if (result != null) {
System.out.println("✅ VM Emission calculation completed for source " + emissionSourceName + ":");
System.out.println(" - VM: " + vm.getVmName());
System.out.println(" - Emission Source: " + emissionSourceName + " (" + percentage + "%)");
System.out.println(" - Power: " + sourceSpecificPower + "W");
System.out.println(" - CO2: " + result.getCo2());
System.out.println(" - Total Emission: " + result.getTotalEmission());
System.out.println(" - Record ID: " + result.getId());
return true;
} else {
System.err.println("❌ Failed to create emission record for VM: " + vm.getVmName() + " - Source: " + emissionSourceName);
return false;
}
} catch (Exception e) {
System.err.println("❌ Error calculating emissions for VM " + vm.getVmName() + " - Source: " + emissionSourceName + ": " + e.getMessage());
return false;
}
}
private MainDataTableCreateInput createVMMainDataTableInput(DataCenter dataCenter, VM vm, Project project, PhysicalMachine pm) { private MainDataTableCreateInput createVMMainDataTableInput(DataCenter dataCenter, VM vm, Project project, PhysicalMachine pm) {
MainDataTableCreateInput input = new MainDataTableCreateInput(); MainDataTableCreateInput input = new MainDataTableCreateInput();
@@ -615,6 +745,76 @@ public class MessageListener {
return input; return input;
} }
private MainDataTableCreateInput createVMMainDataTableInputForSource(DataCenter dataCenter, VM vm, Project project, PhysicalMachine pm, EmissionSource emissionSource, double sourceSpecificPower, Integer percentage) {
MainDataTableCreateInput input = new MainDataTableCreateInput();
// Copy datacenter-level information (if available)
input.setYear("2025");
input.setMonth("07");
// Note: These fields are no longer received in the message
// They need to be set via DataCenter CRUD operations first
if (dataCenter.getArea() != null && !dataCenter.getArea().getCities().isEmpty()) {
input.setCity(dataCenter.getArea().getCities().get(0).getId());
}
if (dataCenter.getArea() != null && !dataCenter.getArea().getDistricts().isEmpty()) {
input.setDistrict(dataCenter.getArea().getDistricts().get(0).getId());
}
if (dataCenter.getSector() != null) {
input.setSector(dataCenter.getSector().getId());
} else {
System.out.println("⚠️ Warning: DataCenter has no sector set - emission calculation may fail");
}
if (dataCenter.getSubSector() != null) {
input.setSubSector(dataCenter.getSubSector().getId());
}
// Use the specific emission source for this calculation
input.setEmissionSource(emissionSource.getId());
if (dataCenter.getActivitySubUnit() != null) {
input.setActivitySubUnit(dataCenter.getActivitySubUnit().getId());
}
if (dataCenter.getConsuptionUnit() != null) {
input.setConsuptionUnit(dataCenter.getConsuptionUnit().getId());
}
// Default to Kapsam-3 if no emission scope is set
input.setScope(dataCenter.getEmissionScope() != null ?
dataCenter.getEmissionScope().getTag().equals("Kapsam-3") : true);
try {
List<Organization> organizations = organizationRepo.findAll();
if (!organizations.isEmpty()) {
input.setOrganization(organizations.get(0).getId());
}
} catch (Exception e) {
System.err.println("❌ Error finding organization: " + e.getMessage());
}
// Set VM-specific fields
input.setVmId(vm.getId());
// Use the source-specific power consumption (percentage of total VM power)
input.setConsuptionAmount(String.valueOf(sourceSpecificPower));
System.out.println("🔍 VM Emission Input for Source:");
System.out.println(" VM ID: " + vm.getId());
System.out.println(" VM Name: " + vm.getVmName());
System.out.println(" Emission Source: " + emissionSource.getTag());
System.out.println(" Percentage: " + percentage + "%");
System.out.println(" Source Power: " + sourceSpecificPower + "W");
System.out.println(" Physical Machine: " + pm.getName());
System.out.println(" Project: " + project.getName());
System.out.println(" DataCenter Sector: " + (dataCenter.getSector() != null ? dataCenter.getSector().getTag() : "NOT SET"));
return input;
}
private void setupSecurityContext() { private void setupSecurityContext() {
User systemUser = new User("system", "", Collections.singletonList(new SimpleGrantedAuthority("dataset_create"))); User systemUser = new User("system", "", Collections.singletonList(new SimpleGrantedAuthority("dataset_create")));
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(systemUser, null, systemUser.getAuthorities()); UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(systemUser, null, systemUser.getAuthorities());

View File

@@ -17,14 +17,14 @@ security.jwt.token.secret-key=secret
app.survey.base-url=http://localhost.com app.survey.base-url=http://localhost.com
spring.rabbitmq.host=188.132.198.145 # spring.rabbitmq.host=188.132.198.145
spring.rabbitmq.port=5672
spring.rabbitmq.username=testuser
spring.rabbitmq.password=JGasF24561AZv2894De
# spring.rabbitmq.host=localhost
# spring.rabbitmq.port=5672 # spring.rabbitmq.port=5672
# spring.rabbitmq.username=guest # spring.rabbitmq.username=testuser
# spring.rabbitmq.password=guest # spring.rabbitmq.password=JGasF24561AZv2894De
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.virtual-host=/ spring.rabbitmq.virtual-host=/
spring.rabbitmq.connection-timeout=20000 spring.rabbitmq.connection-timeout=20000
spring.rabbitmq.template.retry.enabled=true spring.rabbitmq.template.retry.enabled=true

View File

@@ -47,9 +47,12 @@ type Vm {
host: String host: String
flavorName: String flavorName: String
tag: String tag: String
emissionSource: EmissionSourceMap
config: Config config: Config
} }
scalar EmissionSourceMap
type Config { type Config {
id: ID id: ID
cpu: Int cpu: Int

View File

@@ -26,6 +26,7 @@ type MainDataTable {
proteinAmount:Float proteinAmount:Float
burnOrOpenBurn:Boolean burnOrOpenBurn:Boolean
scopeCheck:Boolean scopeCheck:Boolean
vm: Vm
} }