I just created a new repo with the help of Mohamed Faruk, I added a devcontainer so anyone can play with the error. It has the entire project setup so you only need to run the command ./gradlew simulateJava
to get it to run.
I am trying to take an existing Java with Gradle project and make it use Akka actors. When I create an actor system I get an error. This error only seems to happen when I run the code using gradle (but not intelij, more on that later). The code is simply creating a new ActorSystem like the example in the documentation shows. Below is the entire main method.
public final class Main {
private Main() {}
public static void main(String... args) {
var a = ActorSystem.<String>create(Behaviors.logMessages(Behaviors.ignore()), "Machine");
// the code fails on the above line, before anything else can happen
System.out.print("\n".repeat(5));
a.tell("hello");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.print("\n".repeat(5));
a.terminate();
}
}
When I run the above code with the project's run task I get the following output and error.
[WARN] [01/05/2025 13:14:04.410] [Machine-akka.actor.internal-dispatcher-2] [CoordinatedShutdown(akka://Machine)] Task [terminate-system] in phase [actor-system-terminate] threw an exception before its future could be constructed: actor name [user] is not unique!
Here is the full error and stacktrace:
1:30:36 PM: Executing ':frc.robot.Main.main()'…
> Task :eventDeploy
Not running deploy task, skipping commit
> Task :createVersionFile
createVersionFile called. Path /[projectroot]/src/main/java/frc/robot
> Task :compileJava
> Task :processResources UP-TO-DATE
> Task :classes
warning: Supported source version 'RELEASE_17' from annotation processor 'org.gradle.api.internal.tasks.compile.processing.TimeTrackingProcessor' less than -source '22'
1 warning
> Task :frc.robot.Main.main()
[2025-01-05 13:30:38,133] [INFO] [akka.event.slf4j.Slf4jLogger] [Machine-akka.actor.default-dispatcher-4] [] - Slf4jLogger started
[2025-01-05 13:30:38,139] [WARN] [akka.actor.ActorSystemImpl] [Machine-akka.actor.default-dispatcher-4] [akka.actor.ActorSystemImpl(Machine)] - Dev use only. Free keys at https://akka.io/key
[2025-01-05 13:30:38,182] [INFO] [akka.actor.CoordinatedShutdown] [Machine-akka.actor.default-dispatcher-4] [CoordinatedShutdown(akka://Machine)] - Running CoordinatedShutdown with reason [ActorSystemTerminateReason]
[Incubating] Problems report is available at: file:///[projectroot]/build/reports/problems/problems-report.html
BUILD SUCCESSFUL in 1s
5 actionable tasks: 4 executed, 1 up-to-date
1:30:38 PM: Execution finished ':frc.robot.Main.main()'.
Interestingly, it doesn't stop the code due to an error. The code continues "running" but doesnt make it past ActorSystem.create(...)
.
I suspect this is an issue with the project's gradle build system, because when I run the code through Intelij's run button instead of the project's gradle task, it runs perfectly fine and produces the following output:
1:54:41 PM: Executing ':frc.robot.Main.main()'…
> Task :eventDeploy
Not running deploy task, skipping commit
> Task :createVersionFile
createVersionFile called. Path /[projectroot]/src/main/java/frc/robot
> Task :compileJava UP-TO-DATE
> Task :processResources UP-TO-DATE
> Task :classes UP-TO-DATE
> Task :frc.robot.Main.main()
[2025-01-05 13:54:41,812] [INFO] [akka.event.slf4j.Slf4jLogger] [Machine-akka.actor.default-dispatcher-4] [] - Slf4jLogger started
[2025-01-05 13:54:41,818] [WARN] [akka.actor.ActorSystemImpl] [Machine-akka.actor.default-dispatcher-4] [akka.actor.ActorSystemImpl(Machine)] - Dev use only. Free keys at https://akka.io/key
[2025-01-05 13:54:41,861] [INFO] [akka.actor.CoordinatedShutdown] [Machine-akka.actor.default-dispatcher-4] [CoordinatedShutdown(akka://Machine)] - Running CoordinatedShutdown with reason [ActorSystemTerminateReason]
BUILD SUCCESSFUL in 628ms
5 actionable tasks: 3 executed, 2 up-to-date
1:54:41 PM: Execution finished ':frc.robot.Main.main()'.
Which is great. It doesn't log "hello" at all which isn't great but I can deal with that.
I don't know enough about akka to understand why it's attempting to reserve addresses for the user
actor twice, but only in certain contexts.
The gradle project is an FRC project so reproducing it would require installing WPILIB and a bit of struggling, so I wouldn't recommend trying to reproduce it, but if you want to, here is the zip i based the project off of, below is my build.gradle, and here is the WPILIB installer I used. I am using MacOS 15.2.
import edu.wpi.first.gradlerio.GradleRIOPlugin
plugins {
id "java"
id "idea"
id "application"
id "edu.wpi.first.GradleRIO" version "2025.1.1-beta-2"
id "com.peterabeles.gversion" version "1.10"
// id "com.diffplug.spotless" version "6.12.0"
}
java {
sourceCompatibility = JavaVersion.VERSION_22
targetCompatibility = JavaVersion.VERSION_22
}
def ROBOT_MAIN_CLASS = "frc.robot.Main"
// Define my targets (RoboRIO) and artifacts (deployable files)
// This is added by GradleRIO's backing project DeployUtils.
deploy {
targets {
roborio(getTargetTypeClass('RoboRIO')) {
// Team number is loaded either from the .wpilib/wpilib_preferences.json
// or from command line. If not found an exception will be thrown.
// You can use getTeamOrDefault(team) instead of getTeamNumber if you
// want to store a team number in this file.
team = project.frc.getTeamNumber()
debug = project.frc.getDebugOrDefault(false)
artifacts {
// First part is artifact name, 2nd is artifact type
// getTargetTypeClass is a shortcut to get the class type using a string
frcJava(getArtifactTypeClass('FRCJavaArtifact')) {
jvmArgs.add("-XX:+UnlockExperimentalVMOptions")
jvmArgs.add("-XX:GCTimeRatio=5")
jvmArgs.add("-XX:+UseSerialGC")
jvmArgs.add("-XX:MaxGCPauseMillis=50")
// The options below may improve performance, but should only be enabled on the RIO 2
//
// final MAX_JAVA_HEAP_SIZE_MB = 100;
// jvmArgs.add("-Xmx" + MAX_JAVA_HEAP_SIZE_MB + "M")
// jvmArgs.add("-Xms" + MAX_JAVA_HEAP_SIZE_MB + "M")
// jvmArgs.add("-XX:+AlwaysPreTouch")
}
// Static files artifact
frcStaticFileDeploy(getArtifactTypeClass('FileTreeArtifact')) {
files = project.fileTree('src/main/deploy')
directory = '/home/lvuser/deploy'
// Change to true to delete files on roboRIO that no
// longer exist in deploy directory on roboRIO
deleteOldFiles = false
}
}
}
}
}
def deployArtifact = deploy.targets.roborio.artifacts.frcJava
// Set to true to use debug for JNI.
wpi.java.debugJni = false
// Set this to true to enable desktop support.
def includeDesktopSupport = true
// Configuration for AdvantageKit
repositories {
maven {
url = uri("https://maven.pkg.github.com/Mechanical-Advantage/AdvantageKit")
credentials {
username = "Mechanical-Advantage-Bot"
password = "\u0067\u0068\u0070\u005f\u006e\u0056\u0051\u006a\u0055\u004f\u004c\u0061\u0079\u0066\u006e\u0078\u006e\u0037\u0051\u0049\u0054\u0042\u0032\u004c\u004a\u006d\u0055\u0070\u0073\u0031\u006d\u0037\u004c\u005a\u0030\u0076\u0062\u0070\u0063\u0051"
}
}
maven {
url "https://repo.akka.io/maven"
}
mavenCentral()
mavenLocal()
}
task(replayWatch, type: JavaExec) {
mainClass = "org.littletonrobotics.junction.ReplayWatch"
classpath = sourceSets.main.runtimeClasspath
}
def versions = [
ScalaBinary: "2.13"
]
// Defining my dependencies. In this case, WPILib (+ friends), and vendor libraries.
// Also defines JUnit 4.
dependencies {
annotationProcessor wpi.java.deps.wpilibAnnotations()
implementation wpi.java.deps.wpilib()
implementation wpi.java.vendor.java()
roborioDebug wpi.java.deps.wpilibJniDebug(wpi.platforms.roborio)
roborioDebug wpi.java.vendor.jniDebug(wpi.platforms.roborio)
roborioRelease wpi.java.deps.wpilibJniRelease(wpi.platforms.roborio)
roborioRelease wpi.java.vendor.jniRelease(wpi.platforms.roborio)
nativeDebug wpi.java.deps.wpilibJniDebug(wpi.platforms.desktop)
nativeDebug wpi.java.vendor.jniDebug(wpi.platforms.desktop)
simulationDebug wpi.sim.enableDebug()
nativeRelease wpi.java.deps.wpilibJniRelease(wpi.platforms.desktop)
nativeRelease wpi.java.vendor.jniRelease(wpi.platforms.desktop)
simulationRelease wpi.sim.enableRelease()
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.1'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
def akitJson = new groovy.json.JsonSlurper().parseText(new File(projectDir.getAbsolutePath() + "/vendordeps/AdvantageKit.json").text)
annotationProcessor "org.littletonrobotics.akit:akit-autolog:$akitJson.version"
implementation platform("com.typesafe.akka:akka-bom_${versions.ScalaBinary}:2.10.0")
implementation "com.typesafe.akka:akka-actor-typed_${versions.ScalaBinary}"
testImplementation "com.typesafe.akka:akka-actor-testkit-typed_${versions.ScalaBinary}"
annotationProcessor "org.jetbrains:annotations:24.0.0"
implementation "org.jetbrains:annotations:24.0.0"
implementation "ch.qos.logback:logback-classic:1.5.6"
}
test {
useJUnitPlatform()
systemProperty 'junit.jupiter.extensions.autodetection.enabled', 'true'
}
// Simulation configuration (e.g. environment variables).
//
// The sim GUI is *disabled* by default to support running
// AdvantageKit log replay from the command line. Set the
// value to "true" to enable the sim GUI by default (this
// is the standard WPILib behavior).
wpi.sim.addGui().defaultEnabled = true
wpi.sim.addDriverstation()
// Setting up my Jar File. In this case, adding all libraries into the main jar ('fat jar')
// in order to make them all available at runtime. Also adding the manifest so WPILib
// knows where to look for our Robot Class.
jar {
from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
from sourceSets.main.allSource
manifest GradleRIOPlugin.javaManifest(ROBOT_MAIN_CLASS)
duplicatesStrategy = DuplicatesStrategy.INCLUDE
}
// Configure jar and deploy tasks
deployArtifact.jarTask = jar
wpi.java.configureExecutableTasks(jar)
wpi.java.configureTestTasks(test)
// Configure string concat to always inline compile
tasks.withType(JavaCompile) {
options.compilerArgs.add '-XDstringConcat=inline'
}
// Create version file
project.compileJava.dependsOn(createVersionFile)
gversion {
srcDir = "src/main/java/"
classPackage = "frc.robot"
className = "BuildConstants"
dateFormat = "yyyy-MM-dd HH:mm:ss z"
timeZone = "America/New_York"
indent = " "
}
// Create commit with working changes on event branches
task(eventDeploy) {
doLast {
if (project.gradle.startParameter.taskNames.any({ it.toLowerCase().contains("deploy") })) {
def branchPrefix = "event"
def branch = 'git branch --show-current'.execute().text.trim()
def commitMessage = "Update at '${new Date().toString()}'"
if (branch.startsWith(branchPrefix)) {
exec {
workingDir(projectDir)
executable 'git'
args 'add', '-A'
}
exec {
workingDir(projectDir)
executable 'git'
args 'commit', '-m', commitMessage
ignoreExitValue = true
}
println "Committed to branch: '$branch'"
println "Commit message: '$commitMessage'"
} else {
println "Not on an event branch, skipping commit"
}
} else {
println "Not running deploy task, skipping commit"
}
}
}
createVersionFile.dependsOn(eventDeploy)
//// Spotless formatting
//project.compileJava.dependsOn(spotlessApply)
//spotless {
// java {
// target fileTree(".") {
// include "**/*.java"
// exclude "**/build/**", "**/build-*/**"
// }
// toggleOffOn()
// googleJavaFormat()
// removeUnusedImports()
// trimTrailingWhitespace()
// endWithNewline()
// }
// groovyGradle {
// target fileTree(".") {
// include "**/*.gradle"
// exclude "**/build/**", "**/build-*/**"
// }
// greclipse()
// indentWithSpaces(4)
// trimTrailingWhitespace()
// endWithNewline()
// }
// json {
// target fileTree(".") {
// include "**/*.json"
// exclude "**/build/**", "**/build-*/**"
// }
// gson().indentWithSpaces(2)
// }
// format "misc", {
// target fileTree(".") {
// include "**/*.md", "**/.gitignore"
// exclude "**/build/**", "**/build-*/**"
// }
// trimTrailingWhitespace()
// indentWithSpaces(2)
// endWithNewline()
// }
//}
I have checked google and there are plenty of threads that talk about duplicate actors, but none about ActorSystem.create(...)
failing because it attempts to create multiple user
actors.
If you want an easier way to see/reproduce the error see this repo by @Mohamed-Faruk. If you try running it on your computer you will still need to install WPILib but I was able to reproduce my error using his repo.
To run the project you need to use the simulateJava
gradle task. Because this project is designed to deploy to another computer that immediately starts running the project (using the deploy
task) there is the simulateJava
task to allow you to run the code on your computer.
If you have gradle installed you can run the project like this:
gradle simulateJava
if you don't you can use the project's gradle (assuming you have a macos or linux based system):
# you may need the following to run using the built in script
chmod a+x ./gradlew
./gradlew simulateJava
theres a way to run it on windows and may have to do with the gradle.bat file.
I have tried
application.conf
to the resources folder (which does seem to work because when I did that wrong it threw a new error).Since the project didn't use or have Akka before I started adding it, it wouldn't make sense for the project to be conflicting with Akka.
I just am not experienced enough with akka to recognise this error or understand anything about what may be causing it.
What could be causing this problem? I realize diagnosing this is difficult if there isn't much to work with, but I just need clues at what could be causing this. Once I can understand what specifically is different between the two ways of running it, I can change stuff to make it work.
Thanks for sharing the detailed steps that helps me to easily setup your FRC project in my local for debugging. Here are my observations:
Project running with following infra:
After configuring VS Code with WPI extension, install the necessary dependencies as below
Import the project and build the gradle with following run command to inspect the RioLog.
Rerun the same gradle by extending the project with akka [actor model system dependencies] with HelloWorld lightbend examples.
Updated code available in the GitHub for our reference.
Update [Added the application.conf with necessary mailbox configuration resolved the issue for running project via simulateJava command]
To find out the primary error and ensure whether the ActorSystem.create() invoke only once, I added few Info and Error stack trace around the block to shed some more insights behind the error mentioned by @a1cd.
public static void main(String... args) {
try {
unitTestHello();
} catch (Exception e) {
LOG.error("Exception on invoking the main method, caused by", e);
}
}
public static void unitTestHello() {
LOG.info("Invoking unitTestHello");
final ActorSystem<SayHello> system = ActorSystem.create(HelloWorldMain.create(), "hello");
.....
Run the application with simulateJava command to gather the stack trace of mailbox not configured as below:
[main] INFO frc.robot.Main - **Invoking unitTestHello**
[ERROR] [01/15/2025 09:40:53.620] [hello-akka.actor.internal-dispatcher-3] [LocalActorRefProvider] guardian failed, shutting down system
akka.actor.ActorInitializationException: akka://hello/system: exception during creation, root cause message: [actor name [user] is not unique!]
at akka.actor.ActorInitializationException$.apply(Actor.scala:201)
at akka.actor.ActorCell.create(ActorCell.scala:664)
......
[main] ERROR frc.robot.Main - Exception on invoking the main method, caused by
akka.ConfigurationException: **Mailbox Type [akka.actor.typed.default-mailbox] not configured**
at akka.dispatch.Mailboxes.lookupConfigurator(Mailboxes.scala:216)
at akka.dispatch.Mailboxes.lookup(Mailboxes.scala:95)
at akka.actor.LocalActorRefProvider.guardian$lzycompute(ActorRefProvider.scala:574)
.....
at frc.robot.Main.unitTestHello(Main.java:55)
at frc.robot.Main.main(Main.java:41)
[WARN] [01/15/2025 09:40:53.657] [hello-akka.actor.internal-dispatcher-3] [CoordinatedShutdown(akka://hello)] Task [terminate-system] in phase [actor-system-terminate] threw an exception before its future could be constructed: actor name [user] is not unique!