changeset 1766:8df0b80e715e

fix scheduled tasks
author Franklin Schmidt <fschmidt@gmail.com>
date Tue, 06 Jun 2023 14:33:24 -0600
parents 1ffe1e06ea55
children 9157e0d5936e
files src/goodjava/webserver/RequestParser.java src/goodjava/webserver/handlers/DomainHandler.java src/luan/Luan.java src/luan/host/WebHandler.java src/luan/modules/Rpc.luan src/luan/modules/ThreadLuan.java src/luan/modules/http/LuanHandler.java
diffstat 7 files changed, 103 insertions(+), 46 deletions(-) [+]
line wrap: on
line diff
--- a/src/goodjava/webserver/RequestParser.java	Fri May 26 10:29:55 2023 -0600
+++ b/src/goodjava/webserver/RequestParser.java	Tue Jun 06 14:33:24 2023 -0600
@@ -21,7 +21,7 @@
 
 	void parseUrlencoded(String charset) throws ParseException, UnsupportedEncodingException {
 		if( request.body == null ) {
-			logger.warn("body is null\n"+request.rawHead);
+			logger.info("body is null\n"+request.rawHead);
 			return;
 		}
 		this.parser = new Parser(Util.toString(request.body,charset));
@@ -194,7 +194,7 @@
 
 	void parseMultipart() throws ParseException, UnsupportedEncodingException {
 		if( request.body == null ) {
-			logger.warn("body is null\n"+request.rawHead);
+			logger.info("body is null\n"+request.rawHead);
 			return;
 		}
 		String contentType = (String)request.headers.get("content-type");
@@ -274,7 +274,7 @@
 	// improve later
 	void parseJson(String charset) throws UnsupportedEncodingException {
 		if( request.body == null ) {
-			logger.warn("body is null\n"+request.rawHead);
+			logger.info("body is null\n"+request.rawHead);
 			return;
 		}
 		String value = Util.toString(request.body,charset);
--- a/src/goodjava/webserver/handlers/DomainHandler.java	Fri May 26 10:29:55 2023 -0600
+++ b/src/goodjava/webserver/handlers/DomainHandler.java	Tue Jun 06 14:33:24 2023 -0600
@@ -9,6 +9,7 @@
 import java.util.TimerTask;
 import java.util.concurrent.ConcurrentHashMap;
 import goodjava.util.SoftCacheMap;
+import goodjava.util.WeakCacheMap;
 import goodjava.logging.Logger;
 import goodjava.logging.LoggerFactory;
 import goodjava.webserver.Handler;
--- a/src/luan/Luan.java	Fri May 26 10:29:55 2023 -0600
+++ b/src/luan/Luan.java	Tue Jun 06 14:33:24 2023 -0600
@@ -451,7 +451,7 @@
 		public void check(Luan luan,LuanClosure closure,String op,Object... args) throws LuanException;
 	}
 
-	private static String SECURITY_KEY = "Luan.Security";
+	private static final String SECURITY_KEY = "Luan.Security";
 
 	public static void checkSecurity(Luan luan,String op,Object... args) throws LuanException {
 		check(luan,1,op,args);
--- a/src/luan/host/WebHandler.java	Fri May 26 10:29:55 2023 -0600
+++ b/src/luan/host/WebHandler.java	Tue Jun 06 14:33:24 2023 -0600
@@ -1,7 +1,14 @@
 package luan.host;
 
+import java.io.Closeable;
 import java.io.File;
 import java.io.IOException;
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Method;
+import java.util.Set;
+import java.util.Collections;
+import java.util.concurrent.ConcurrentHashMap;
 import goodjava.logging.Logger;
 import goodjava.logging.LoggerFactory;
 import goodjava.io.IoUtils;
@@ -23,6 +30,7 @@
 import luan.LuanException;
 import luan.LuanTable;
 import luan.LuanFunction;
+import luan.LuanJavaFunction;
 import luan.LuanClosure;
 import luan.LuanRuntimeException;
 import luan.modules.http.LuanHandler;
@@ -34,7 +42,7 @@
 	private static final Logger logger = LoggerFactory.getLogger(WebHandler.class);
 	private static final long days30 = 1000L*60*60*24*30;
 
-	private static final class MyHandler implements Handler {
+	private static final class MyHandler implements Handler, Closeable {
 		private final Handler handler;
 		final LuanHandler luanHandler;
 
@@ -46,6 +54,11 @@
 		@Override public Response handle(Request request) {
 			return handler.handle(request);
 		}
+
+		@Override public void close() {
+			Object obj = dontGc.remove(this);
+			luanHandler.close();
+		}
 	}
 
 	private static final DomainHandler.Factory factory = new DomainHandler.Factory() {
@@ -76,6 +89,13 @@
 			} finally {
 				LuanLogger.endThreadLogging();
 			}
+			Fns fns = new Fns();
+			try {
+				LuanTable Http = (LuanTable)luan.require("luan:http/Http.luan");
+				Http.put( luan, "dont_gc", new LuanJavaFunction(dontGcMethod,fns) );
+			} catch(LuanException e) {
+				throw new RuntimeException(e);
+			}
 			security(luan,dirStr);
 			LuanHandler luanHandler = new LuanHandler(luan,domain);
 
@@ -93,7 +113,9 @@
 			handler = new SafeHandler(handler);
 			handler = new LogHandler(handler,LogHandler.dirLogger(new File(logDir),days30));
 
-			return new MyHandler(handler,luanHandler);
+			MyHandler myHandler = new MyHandler(handler,luanHandler);
+			fns.set(myHandler);
+			return myHandler;
 		}
 	};
 
@@ -183,4 +205,39 @@
 		Luan.setSecurity(luan,security);
 	}
 
+
+	private static final Set<MyHandler> dontGc = Collections.newSetFromMap(new ConcurrentHashMap<MyHandler,Boolean>());
+	private static final Method dontGcMethod;
+	static {
+		try {
+			dontGcMethod = WebHandler.Fns.class.getMethod( "dont_gc" );
+		} catch(NoSuchMethodException e) {
+			throw new RuntimeException(e);
+		}
+	}
+	public static final class Fns {
+		private Reference<MyHandler> ref = null;
+		private boolean dont = false;
+
+		private void set(MyHandler myHandler) {
+			if( dont ) {
+				dontGc.add(myHandler);
+			} else {
+				ref = new WeakReference<MyHandler>(myHandler);
+			}
+		}
+
+		public void dont_gc() throws LuanException {
+			logger.info("dont_gc");
+			if( ref == null ) {
+				dont = true;
+			} else {
+				MyHandler mh = ref.get();
+				if( mh == null )
+					throw new LuanException("HTTP handler has been garbage collected");
+				dontGc.add(mh);
+			}
+		}
+	}
+
 }
--- a/src/luan/modules/Rpc.luan	Fri May 26 10:29:55 2023 -0600
+++ b/src/luan/modules/Rpc.luan	Tue Jun 06 14:33:24 2023 -0600
@@ -220,7 +220,7 @@
 						responder.respond()
 					end
 				catch e
-					logger.warn(e)
+					logger.info(e)
 				finally
 					responder and responder.after_close and responder.after_close()
 				end
--- a/src/luan/modules/ThreadLuan.java	Fri May 26 10:29:55 2023 -0600
+++ b/src/luan/modules/ThreadLuan.java	Tue Jun 06 14:33:24 2023 -0600
@@ -1,7 +1,6 @@
 package luan.modules;
 
 import java.io.Closeable;
-import java.util.Arrays;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.HashMap;
@@ -26,6 +25,11 @@
 public final class ThreadLuan {
 	private static final Logger logger = LoggerFactory.getLogger(ThreadLuan.class);
 
+	public static final String CLOSEABLES = "Luan.closeables";
+	public interface Closeables {
+		public void addCloseable(Closeable c) throws LuanException;
+	}
+
 	private static final Executor exec = Executors.newCachedThreadPool();
 	public static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
 
@@ -50,8 +54,6 @@
 		exec.execute(runnable(luan,fn));
 	}
 
-	private static final Map<String,ScheduledFuture> scheduleds = new WeakCacheMap<String,ScheduledFuture>();
-
 	private static void cancel(ScheduledFuture sf,String src) {
 		boolean b = sf.cancel(false);
 		if( !sf.isCancelled() )
@@ -82,17 +84,13 @@
 		Number delay = Utils.removeNumber(options,"delay");
 		Number repeatingDelay = Utils.removeNumber(options,"repeating_delay");
 		Number repeatingRate = Utils.removeNumber(options,"repeating_rate");
-		Boolean dontGc = Utils.removeBoolean(options,"dont_gc");
 		String id = Utils.removeString(options,"id");
+		if( id != null )
+			logger.error("thread option 'id' is obsolete: "+id);
 		if( repeatingDelay!=null && repeatingRate!=null )
 			throw new LuanException("can't define both repeating_delay and repeating_rate");
 		boolean repeating = repeatingDelay!=null || repeatingRate!=null;
 		Utils.checkEmpty(options);
-		if( id != null ) {
-			ScheduledFuture sf = scheduleds.remove(id);
-			if( sf != null )
-				cancel(sf,"id "+id);
-		}
 		final Runnable r = runnable(newLuan,fn);
 		final ScheduledFuture sf;
 		if( repeatingDelay != null ) {
@@ -109,16 +107,18 @@
 			scheduler.schedule(r,0L,TimeUnit.MILLISECONDS);
 			return;
 		}
-		if( !Boolean.TRUE.equals(dontGc) ) {
-			Object c = new Object() {
+		Closeables cs = (Closeables)luan.registry().get(CLOSEABLES);
+		if( cs != null ) {
+			Closeable cl = new Closeable() {
+				public void close() {
+					cancel(sf,"close");
+				}
 				protected void finalize() throws Throwable {
-					cancel(sf,"gc");
+					cancel(sf,"gc");  // cancel on gc
 				}
 			};
-			luan.registry().put(c,c);  // cancel on gc
+			cs.addCloseable(cl);
 		}
-		if( id != null )
-			scheduleds.put(id,sf);
 	}
 
 
--- a/src/luan/modules/http/LuanHandler.java	Fri May 26 10:29:55 2023 -0600
+++ b/src/luan/modules/http/LuanHandler.java	Tue Jun 06 14:33:24 2023 -0600
@@ -10,9 +10,6 @@
 import java.net.BindException;
 import java.util.List;
 import java.util.ArrayList;
-import java.util.Set;
-import java.util.Collections;
-import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 import goodjava.logging.Logger;
@@ -30,32 +27,30 @@
 import luan.LuanException;
 import luan.modules.PackageLuan;
 import luan.modules.BasicLuan;
+import luan.modules.ThreadLuan;
 import luan.modules.logging.LuanLogger;
 
 
 public final class LuanHandler implements Handler, Closeable {
 	private static final Logger logger = LoggerFactory.getLogger(LuanHandler.class);
 
-	private static final Set<LuanHandler> dontGc = Collections.newSetFromMap(new ConcurrentHashMap<LuanHandler,Boolean>());
-
 	private final Luan luanInit;
 	private final String domain;
 	private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
 	private volatile Luan currentLuan;
 	private volatile boolean isDisabled = false;
 	private volatile boolean didInit;
+	private final List<Closeable> closeables = new ArrayList<Closeable>();
 
 	private static final Method resetLuanMethod;
 	private static final Method evalInRootMethod;
 	private static final Method disableLuanMethod;
-	private static final Method dontGcMethod;
 	private static final Method testAsInitMethod;
 	static {
 		try {
 			resetLuanMethod = LuanHandler.Fns.class.getMethod( "reset_luan" );
 			evalInRootMethod = LuanHandler.Fns.class.getMethod( "eval_in_root", String.class );
 			disableLuanMethod = LuanHandler.Fns.class.getMethod( "disable_luan" );
-			dontGcMethod = LuanHandler.Fns.class.getMethod( "dont_gc" );
 			testAsInitMethod = LuanHandler.Fns.class.getMethod( "test_as_init", String.class, String.class );
 		} catch(NoSuchMethodException e) {
 			throw new RuntimeException(e);
@@ -65,26 +60,28 @@
 	public LuanHandler(Luan luanInit,String domain) {
 		this.luanInit = luanInit;
 		this.domain = domain;
+		Fns fns = new Fns(this);
 		try {
-			Fns fns = new Fns(this);
 			LuanTable Http = (LuanTable)luanInit.require("luan:http/Http.luan");
 			if( Http.get(luanInit,"reset_luan") == null )
 				Http.put( luanInit, "reset_luan", new LuanJavaFunction(resetLuanMethod,fns) );
 			Http.put( luanInit, "eval_in_root", new LuanJavaFunction(evalInRootMethod,fns) );
 			Http.put( luanInit, "disable_luan", new LuanJavaFunction(disableLuanMethod,fns) );
-			Http.put( luanInit, "dont_gc", new LuanJavaFunction(dontGcMethod,fns) );
 			Http.put( luanInit, "test_as_init", new LuanJavaFunction(testAsInitMethod,fns) );
 		} catch(LuanException e) {
 			throw new RuntimeException(e);
 		}
+		if( luanInit.registry().get(ThreadLuan.CLOSEABLES) != null )
+			throw new RuntimeException(ThreadLuan.CLOSEABLES+" already set");
+		luanInit.registry().put(ThreadLuan.CLOSEABLES,fns);
 		if( domain != null )
-			logger.info("new "+domain);
+			logger.warn("new "+domain);
 		newLuan();
 	}
 
 	protected void finalize() throws Throwable {
 		if( domain != null )
-			logger.info("gc "+domain);
+			logger.warn("gc "+domain);
 	}
 
 	private void init(Luan luan) throws LuanException {
@@ -146,9 +143,16 @@
 		}
 	}
 
-	public void close() {
-		Object obj = dontGc.remove(this);
-		//logger.info("close "+domain+" "+(obj!=null));
+	@Override public void close() {
+		synchronized(currentLuan) {
+			for( Closeable c : closeables ) {
+				try {
+					c.close();
+				} catch(IOException e) {
+					logger.error(c.toString(),e);
+				}
+			}
+		}
 	}
 
 	public Object call_rpc(String fnName,Object... args) throws LuanException {
@@ -215,12 +219,7 @@
 		}
 	}
 
-	private void dont_gc() {
-		dontGc.add(this);
-		//logger.info("dont_gc "+domain);
-	}
-
-	public static final class Fns {
+	public static final class Fns implements ThreadLuan.Closeables {
 		private final Reference<LuanHandler> ref;
 
 		private Fns(LuanHandler lh) {
@@ -234,6 +233,10 @@
 			return lh;
 		}
 
+		@Override public void addCloseable(Closeable c) throws LuanException {
+			lh().closeables.add(c);
+		}
+
 		public void reset_luan() throws LuanException {
 			lh().reset_luan();
 		}
@@ -246,10 +249,6 @@
 			lh().eval_in_root(text);
 		}
 
-		public void dont_gc() throws LuanException {
-			lh().dont_gc();
-		}
-
 		public void test_as_init(String text,String sourceName) throws LuanException {
 			lh().test_as_init(text,sourceName);
 		}