SimpleFAN: Extending Oracle RAC High Availability to Custom Connection Management
Leverage Oracle’s SimpleFAN API to build RAC-aware connection managers with full FAN event support
Oracle Real Application Clusters (RAC) provides enterprise applications with robust high availability through Fast Application Notification (FAN) events. While Oracle Universal Connection Pool (UCP) and Oracle JDBC drivers offer comprehensive FAN support out of the box, there are scenarios where developers need to build custom connection management solutions or integrate FAN capabilities into existing application architectures.
SimpleFAN is Oracle’s standalone Java API that enables any Java application to harness the full power of Oracle RAC FAN events, providing the building blocks for sophisticated, RAC-aware connection management systems.
When to Use SimpleFAN
SimpleFAN is ideal when you’re building:
- Custom connection pooling solutions tailored to specific application requirements
- Application-level connection managers with specialized routing logic
- Integration layers that need RAC awareness for existing systems
- Third-party JDBC drivers for the Oracle Database
- Middleware components that require direct FAN event handling
If you’re starting a new project, Oracle Universal Connection Pool remains the recommended solution for comprehensive Oracle RAC integration.
Understanding FAN Events
Oracle RAC FAN events provide real-time notifications about cluster state changes. SimpleFAN exposes four essential event types:
- Service Up Events – Database services becoming available
- Service Down Events – Services becoming unavailable (planned or unplanned)
- Node Down Events – Complete node failures
- Load Advisory Events – Real-time load balancing metrics
Prerequisites and Setup
Dependencies
SimpleFAN is available through Maven Central. Use the latest versions:
<dependency>
<groupId>com.oracle.ojdbc</groupId>
<artifactId>simplefan</artifactId>
<version>23.8.0.25.04</version>
</dependency>
<dependency>
<groupId>com.oracle.ojdbc</groupId>
<artifactId>ons</artifactId>
<version>23.8.0.25.04</version>
</dependency>
Service Configuration
Critical: Your Oracle RAC service must be configured with FAN enabled for SimpleFAN to receive events:
# Create or modify a service with FAN enabled
srvctl add service -db myrac -service myapp_service -notification TRUE
# Or modify existing service
srvctl modify service -db myrac -service myapp_service -notification TRUE
# Verify FAN configuration
srvctl config service -db myrac -service myapp_service
The Hybrid Approach: Database-Driven ONS Configuration
One of SimpleFAN’s most powerful capabilities is retrieving ONS (Oracle Notification Service) configuration directly from the database connection – the same method Oracle’s JDBC driver uses internally. This eliminates manual ONS configuration and ensures consistency with Oracle’s native approach.
Core Implementation
import oracle.simplefan.*;
import oracle.jdbc.pool.OracleDataSource;
import java.sql.Connection;
import java.util.Properties;
import java.util.logging.Logger;
public class SimpleFanConnectionManager implements FanEventListener {
private static final Logger logger = Logger.getLogger(SimpleFanConnectionManager.class.getName());
private FanManager fanManager;
private FanSubscription fanSubscription;
private String serviceName;
public void initialize(String serviceName) {
this.serviceName = serviceName;
try {
// Step 1: Get ONS config from database like Oracle JDBC driver
String onsConfig = getONSConfigFromDatabase();
// Step 2: Initialize SimpleFAN with retrieved config
initializeSimpleFan(onsConfig);
} catch (Exception e) {
logger.severe("Failed to initialize SimpleFAN: " + e.getMessage());
throw new RuntimeException("SimpleFAN initialization failed", e);
}
}
}
Database ONS Configuration Retrieval
This method mirrors Oracle’s internal approach for ONS discovery:
private String getONSConfigFromDatabase() throws SQLException {
OracleDataSource ods = new OracleDataSource();
// Disable OJDBC's built-in FAN support since we're using standalone SimpleFAN
ods.setURL("jdbc:oracle:thin:@//hostname:1521/servicename?oracle.jdbc.fanEnabled=false");
ods.setUser("username");
ods.setPassword("password");
Connection dbConnection = ods.getConnection();
try {
if (dbConnection instanceof oracle.jdbc.OracleConnection) {
oracle.jdbc.OracleConnection oracleConn =
(oracle.jdbc.OracleConnection) dbConnection;
Properties serverInfo = oracleConn.getServerSessionInfo();
// Get AUTO ONS config - Oracle's standard method
String autoONSConfig = serverInfo.getProperty("AUTH_ONS_CONFIG");
if (autoONSConfig != null && !autoONSConfig.isEmpty()) {
logger.info("Found AUTO ONS config: " + autoONSConfig);
return autoONSConfig;
} else {
throw new SQLException("AUTO ONS config not available from database connection");
}
} else {
throw new SQLException("Connection is not an Oracle connection");
}
} finally {
dbConnection.close();
}
}
SimpleFAN Initialization
Initialize SimpleFAN using Oracle’s native configuration approach:
private void initializeSimpleFan(String onsConfigStr) {
try {
logger.info("Initializing SimpleFAN with ONS config: " + onsConfigStr);
// Get FanManager singleton instance
fanManager = FanManager.getInstance();
// Configure ONS using Oracle's method
Properties onsProps = new Properties();
onsProps.setProperty("onsRemoteConfig", onsConfigStr);
fanManager.configure(onsProps);
// Create service subscription
Properties subscriptionProps = new Properties();
subscriptionProps.setProperty("serviceName", serviceName);
fanSubscription = fanManager.subscribe(subscriptionProps);
fanSubscription.addListener(this);
logger.info("SimpleFAN subscription created for service: " + serviceName);
} catch (Exception e) {
logger.severe("SimpleFAN initialization failed: " + e.getMessage());
throw new RuntimeException("Failed to initialize SimpleFAN", e);
}
}
Event Handler Implementation
Implement the FanEventListener interface to respond to Oracle RAC events:
Service Down Event Handling
@Override
public void handleEvent(ServiceDownEvent event) {
logger.warning("SERVICE DOWN event received for: " + event.getServiceName());
System.out.println("\n=== SERVICE DOWN EVENT ===");
System.out.println("Service: " + event.getServiceName());
System.out.println("Time: " + event.getTimestamp());
System.out.println("Reason: " + event.getReason());
System.out.println("Kind: " + event.getKind());
System.out.println("Database: " + event.getDatabaseUniqueName());
if (event.getKind().toString().equals("MEMBER")) {
// Specific instance down
String instanceName = event.getServiceMemberEvent().getInstanceName();
String nodeName = event.getServiceMemberEvent().getNodeName();
System.out.println("Instance: " + instanceName);
System.out.println("Node: " + nodeName);
// Handle instance-specific outage
handleInstanceDown(instanceName, nodeName);
} else {
// Entire service down
handleServiceDown(event.getServiceName());
}
System.out.println("========================\n");
}
Load Advisory Event Handling
@Override
public void handleEvent(LoadAdvisoryEvent event) {
logger.info("LOAD ADVISORY event received");
System.out.println("\n=== LOAD ADVISORY EVENT ===");
System.out.println("Service: " + event.getServiceName());
System.out.println("Database: " + event.getDatabaseUniqueName());
System.out.println("Instance: " + event.getInstanceName());
System.out.println("Service Quality: " + event.getServiceQuality());
System.out.println("Percent: " + event.getPercent());
System.out.println("Time: " + event.getTimestamp());
System.out.println("==========================\n");
// Implement load balancing logic
updateLoadBalancing(event.getInstanceName(),
event.getServiceQuality(),
event.getPercent());
}
Node Down Event Handling
@Override
public void handleEvent(NodeDownEvent event) {
logger.warning("NODE DOWN event received for: " + event.getNodeName());
System.out.println("\n=== NODE DOWN EVENT ===");
System.out.println("Node: " + event.getNodeName());
System.out.println("Time: " + event.getTimestamp());
System.out.println("======================\n");
// Handle complete node failure
handleNodeDown(event.getNodeName());
}
Example Log Output
When SimpleFAN is running and Oracle RAC events occur, you’ll see console output like this:
Application Startup
INFO: Found AUTO ONS config: nodes=racnode1:6200,racnode2:6200
INFO: Initializing SimpleFAN with ONS config: nodes=racnode1:6200,racnode2:6200
INFO: SimpleFAN subscription created for service: myapp_service
Normal Load Advisory Event
INFO: LOAD ADVISORY event received
=== LOAD ADVISORY EVENT ===
Service: myapp_service
Database: MYRAC
Instance: myrac_1
Service Quality: 25
Percent: 35
Time: 2025-06-23T14:25:30.123Z
==========================
Planned Instance Maintenance
WARNING: SERVICE DOWN event received for: myapp_service
=== SERVICE DOWN EVENT ===
Service: myapp_service
Time: 2025-06-23T14:30:45.456Z
Reason: USER
Kind: MEMBER
Database: MYRAC
Instance: myrac_1
Node: racnode1
========================
INFO: Removed connections to instance: myrac_1
Load Shifts to Remaining Instance
INFO: LOAD ADVISORY event received
=== LOAD ADVISORY EVENT ===
Service: myapp_service
Database: MYRAC
Instance: myrac_2
Service Quality: 75
Percent: 85
Time: 2025-06-23T14:31:00.789Z
==========================
Instance Returns Online
INFO: SERVICE UP event received for: myapp_service
=== SERVICE UP EVENT ===
Service: myapp_service
Time: 2025-06-23T14:35:12.321Z
Kind: MEMBER
Database: MYRAC
Instance: myrac_1
Node: racnode1
========================
Complete Node Failure
WARNING: NODE DOWN event received for: racnode2
=== NODE DOWN EVENT ===
Node: racnode2
Time: 2025-06-23T14:40:15.987Z
======================
WARNING: SERVICE DOWN event received for: myapp_service
=== SERVICE DOWN EVENT ===
Service: myapp_service
Time: 2025-06-23T14:40:16.123Z
Reason: FAILURE
Kind: MEMBER
Database: MYRAC
Instance: myrac_2
Node: racnode2
========================
INFO: Removed connections to instance: myrac_2
Connection Manager Integration
Custom Connection Manager Example
Here’s how to integrate SimpleFAN into a custom connection manager:
public class RACConnectionManager {
private SimpleFanConnectionManager fanManager;
private ConnectionPool connectionPool;
public void initialize(String serviceName) {
// Initialize your connection pool
connectionPool = new CustomConnectionPool();
// Initialize SimpleFAN
fanManager = new SimpleFanConnectionManager();
fanManager.initialize(serviceName);
}
// Implement event response methods
private void handleInstanceDown(String instanceName, String nodeName) {
// Remove connections to specific instance
connectionPool.removeConnectionsToInstance(instanceName);
logger.info("Removed connections to instance: " + instanceName);
}
private void handleServiceDown(String serviceName) {
// Handle complete service unavailability
connectionPool.markServiceUnavailable(serviceName);
logger.warning("Service marked as unavailable: " + serviceName);
}
private void updateLoadBalancing(String instanceName, String serviceQuality, int percent) {
// Adjust connection routing based on load metrics
connectionPool.updateInstanceWeight(instanceName, percent);
}
}
Production Considerations
Clean Shutdown
Always implement proper cleanup:
public void shutdown() {
logger.info("Shutting down SimpleFAN connection manager...");
if (fanSubscription != null) {
try {
fanSubscription.close();
logger.info("SimpleFAN subscription closed successfully");
} catch (Exception e) {
logger.warning("Error closing SimpleFAN subscription: " + e.getMessage());
}
}
}
// Register shutdown hook
Runtime.getRuntime().addShutdownHook(new Thread(this::shutdown));
Testing Your Implementation
Use Oracle’s srvctl commands to test FAN event handling:
# Planned service down with drain timeout and immediate stop option
srvctl stop service -db myrac -service myapp_service -instance myrac_1 -drain_timeout 30 -stopoption IMMEDIATE
# Service up
srvctl start service -db myrac -service myapp_service -instance myrac_1
Monitor your application logs to verify that SimpleFAN receives and processes these events correctly.
Key Benefits
Implementing SimpleFAN in custom connection managers provides:
- Oracle RAC Awareness: Real-time notification of cluster state changes
- Zero-Downtime Maintenance: Graceful handling of planned Oracle operations
- Intelligent Connection Routing: Load balancing based on actual cluster metrics
- Faster Failure Detection: Immediate notification of outages
- Enterprise-Grade Reliability: Leverage Oracle’s proven high availability infrastructure
Conclusion
SimpleFAN empowers developers to build sophisticated, Oracle RAC-aware connection management solutions while leveraging Oracle’s proven high availability infrastructure. The hybrid approach demonstrated here ensures your custom connection manager integrates seamlessly with Oracle’s native FAN event system.
By implementing SimpleFAN, you can create connection management solutions that respond intelligently to Oracle RAC cluster changes, providing your applications with enterprise-grade database high availability.
