SoFunction
Updated on 2025-03-08

Source code interpretation of PowerJob LockService method workflow

sequence

This article mainly studies PowerJob's LockService

LockService

tech/powerjob/server/extension/

public interface LockService {
    /**
      * Lock (acquire lock), return immediately, will not block waiting for lock
      * @param name Lock name
      * @param maxLockTime Maximum lock-holding time, unit milliseconds (ms)
      * @return true -> Lock was obtained, false -> Lock was not obtained
      */
    boolean tryLock(String name, long maxLockTime);
    /**
      * Release the lock
      * @param name Lock name
      */
    void unlock(String name);
}
The LockService interface defines tryLock and unlock methods

DatabaseLockService

tech/powerjob/server/extension/defaultimpl/

@Slf4j
@Service
public class DatabaseLockService implements LockService {
    private final String ownerIp;
    private final OmsLockRepository omsLockRepository;
    @Autowired
    public DatabaseLockService(OmsLockRepository omsLockRepository) {
         = ();
         = omsLockRepository;
        ().addShutdownHook(new Thread(() -> {
            int num = (ownerIp);
            ("[DatabaseLockService] execute shutdown hook, release all lock(owner={},num={})", ownerIp, num);
        }));
    }
    @Override
    public boolean tryLock(String name, long maxLockTime) {
        OmsLockDO newLock = new OmsLockDO(name, ownerIp, maxLockTime);
        try {
            (newLock);
            return true;
        } catch (DataIntegrityViolationException ignore) {
        } catch (Exception e) {
            ("[DatabaseLockService] write lock to database failed, lockName = {}.", name, e);
        }
        OmsLockDO omsLockDO = (name);
        long lockedMillions = () - ().getTime();
        // The lock timed out, force release the lock and try to obtain it again        if (lockedMillions > ()) {
            ("[DatabaseLockService] The lock[{}] already timeout, will be unlocked now.", omsLockDO);
            unlock(name);
            return tryLock(name, maxLockTime);
        }
        return false;
    }
    @Override
    public void unlock(String name) {
        try {
            CommonUtils.executeWithRetry0(() -> (name));
        }catch (Exception e) {
            ("[DatabaseLockService] unlock {} failed.", name, e);
        }
    }
}
DatabaseLockService implements LockService based on the database. Its constructor relies on OmsLockRepository and registers ShutdownHook at the same time. Executes (ownerIp) when it is closed. Its tryLock method creates OmsLockDO and then executes it. If it succeeds, it returns. If there is an exception, it will calculate the locking time by finding omsLockDO. If it exceeds MaxLockTime, execute unlock and tryLock again; its unlock execution

tech/powerjob/common/utils/

public static String getLocalHost() {
        if (HOST_ADDRESS != null) {
            return HOST_ADDRESS;
        }
        String addressFromJVM = (PowerJobDKey.BIND_LOCAL_ADDRESS);
        if ((addressFromJVM)) {
            ("[Net] use address from[{}]: {}", PowerJobDKey.BIND_LOCAL_ADDRESS, addressFromJVM);
            return HOST_ADDRESS = addressFromJVM;
        }
        InetAddress address = getLocalAddress();
        if (address != null) {
            return HOST_ADDRESS = ();
        }
        return LOCALHOST_VALUE;
    }
    public static InetAddress getLocalAddress() {
        if (LOCAL_ADDRESS != null) {
            return LOCAL_ADDRESS;
        }
        InetAddress localAddress = getLocalAddress0();
        LOCAL_ADDRESS = localAddress;
        return localAddress;
    }    
    private static InetAddress getLocalAddress0() {
        // @since 2.7.6, choose the {@link NetworkInterface} first
        try {
            InetAddress addressOp = getFirstReachableInetAddress( findNetworkInterface());
            if (addressOp != null) {
                return addressOp;
            }
        } catch (Throwable e) {
            ("[Net] getLocalAddress0 failed.", e);
        }
        InetAddress localAddress = null;
        try {
            localAddress = ();
            Optional<InetAddress> addressOp = toValidAddress(localAddress);
            if (()) {
                return ();
            }
        } catch (Throwable e) {
            ("[Net] getLocalAddress0 failed.", e);
        }
        return localAddress;
    }
NetUtils' getLocalHost first determines whether HOST_ADDRESS has a value. If so, return it directly. Otherwise, read it from the system attribute first. If it cannot be read, take LOCAL_ADDRESS. If LOCAL_ADDRESS is null, get it through getLocalAddress0

OmsLockDO

tech/powerjob/server/persistence/remote/model/

@Data
@Entity
@NoArgsConstructor
@Table(uniqueConstraints = {@UniqueConstraint(name = "uidx01_oms_lock", columnNames = {"lockName"})})
public class OmsLockDO {

    @Id
    @GeneratedValue(strategy = , generator = "native")
    @GenericGenerator(name = "native", strategy = "native")
    private Long id;

    private String lockName;

    private String ownerIP;
    /**
      * Maximum lock-holding time
      */
    private Long maxLockTime;

    private Date gmtCreate;

    private Date gmtModified;

    public OmsLockDO(String lockName, String ownerIP, Long maxLockTime) {
         = lockName;
         = ownerIP;
         = maxLockTime;
         = new Date();
         = ;
    }
}
OmsLockDO defines lockName as a unique index, and it also defines ownerIP and maxLockTime.

OmsLockRepository

tech/powerjob/server/persistence/remote/repository/

public interface OmsLockRepository extends JpaRepository&lt;OmsLockDO, Long&gt; {

    @Modifying
    @Transactional(rollbackOn = )
    @Query(value = "delete from OmsLockDO where lockName = ?1")
    int deleteByLockName(String lockName);

    OmsLockDO findByLockName(String lockName);

    @Modifying
    @Transactional(rollbackOn = )
    int deleteByOwnerIP(String ip);
}
OmsLockRepository inherits JpaRepository, which defines deleteByLockName, findByLockName, deleteByOwnerIP methods

summary

The LockService interface defines tryLock and unlock methods; DatabaseLockService implements LockService based on the database. Its constructor relies on OmsLockRepository and registers ShutdownHook at the same time, executes (ownerIp); its tryLock method creates OmsLockDO, and then executes it. If successful, it returns. If there is an exception, it will calculate the locking time by finding omsLockDO. If it exceeds MaxLockTime, execute unlock and retryLock; its unlock execution.

The above is the detailed interpretation of the source code of the PowerJob LockService method workflow. For more information about PowerJob LockService, please follow my other related articles!